Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TGeoChecker.cxx
Go to the documentation of this file.
1// @(#)root/geom:$Id$
2// Author: Andrei Gheata 01/11/01
3// CheckGeometry(), CheckOverlaps() by Mihaela Gheata
4
5/*************************************************************************
6 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
7 * All rights reserved. *
8 * *
9 * For the licensing terms see $ROOTSYS/LICENSE. *
10 * For the list of contributors see $ROOTSYS/README/CREDITS. *
11 *************************************************************************/
12
13/** \class TGeoChecker
14\ingroup Geometry_painter
15
16Geometry checking package.
17
18TGeoChecker class provides several geometry checking methods. There are two
19types of tests that can be performed. One is based on random sampling or
20ray-tracing and provides a visual check on how navigation methods work for
21a given geometry. The second actually checks the validity of the geometry
22definition in terms of overlapping/extruding objects. Both types of checks
23can be done for a given branch (starting with a given volume) as well as for
24the geometry as a whole.
25
26#### TGeoChecker::CheckPoint(Double_t x, Double_t y, Double_t z)
27
28This method can be called directly from the TGeoManager class and print a
29report on how a given point is classified by the modeller: which is the
30full path to the deepest node containing it, and the (under)estimation
31of the distance to the closest boundary (safety).
32
33#### TGeoChecker::RandomPoints(Int_t npoints)
34
35Can be called from TGeoVolume class. It first draws the volume and its
36content with the current visualization settings. Then randomly samples points
37in its bounding box, plotting in the geometry display only the points
38classified as belonging to visible volumes.
39
40#### TGeoChecker::RandomRays(Int_t nrays, Double_t startx, starty, startz)
41
42Can be called and acts in the same way as the previous, but instead of points,
43rays having random isotropic directions are generated from the given point.
44A raytracing algorithm propagates all rays until they exit geometry, plotting
45all segments crossing visible nodes in the same color as these.
46
47#### TGeoChecker::Test(Int_t npoints)
48
49Implementation of TGeoManager::Test(). Computes the time for the modeller
50to find out "Where am I?" for a given number of random points.
51
52#### TGeoChecker::LegoPlot(ntheta, themin, themax, nphi, phimin, phimax,...)
53
54Implementation of TGeoVolume::LegoPlot(). Draws a spherical radiation length
55lego plot for a given volume, in a given theta/phi range.
56
57#### TGeoChecker::Weight(Double_t precision)
58
59Implementation of TGeoVolume::Weight(). Estimates the total weight of a given
60volume by material sampling. Accepts as input the desired precision.
61
62#### TGeoChecker::CheckOverlaps(Double_t ovlp, Option_t *option)
63Checks the geometry definition for illegal overlaps and illegal extrusions
64within a selected geometry hierarchy.
65
66An **illegal overlap** is reported when two placed volumes (typically sibling
67daughters of the same mother, or a daughter against the mother depending on
68the traversal) occupy a common region of space larger than the allowed tolerance.
69In practical terms, a set of test points generated on the surface of one
70candidate is found **inside** the other candidate volume by more than the configured
71tolerance.
72
73An **illegal extrusion** is reported when a placed daughter volume has surface
74points that lie outside its expected container region (e.g. outside its mother
75or outside the allowed placement region as defined by the geometry navigation
76context), again beyond the configured tolerance.
77
78The overlap checking is performed in three stages:
79
801. Candidate search and filtering
81The checker traverses the requested hierarchy and generates candidate pairs.
82Candidate pairs are aggressively reduced using fast bounding checks (including
83oriented bounding box filters) before any expensive navigation tests are performed.
84
852. Surface point generation and caching
86For each distinct TGeoShape appearing in the candidate list, the checker generates
87a set of surface sampling points and caches them. The cached sampling depends on
88the current meshing policy (see tuning below).
89
903. Exact overlap/extrusion tests (navigation-based)
91The final test uses TGeo navigation (Contains, Safety, frame transforms) to evaluate
92whether sampled surface points violate the overlap/extrusion constraints. This final
93stage can run in parallel when ROOT Implicit MT is enabled.
94
95* Usage:
96- Check the full geometry
97 - Call from the manager:
98
99~~~{.cpp}
100gGeoManager->CheckOverlaps(ovlp);
101~~~
102
103- Check only a sub-hierarchy
104 - Call from a volume:
105
106~~~{.cpp}
107gGeoManager->GetTopVolume()->CheckOverlaps(ovlp);
108~~~
109
110This checks overlaps/extrusions for the selected volume and its daughters
111(recursively), without requiring a full-geometry check.
112
113* Parameters:
114~~~{.cpp}
115ovlp
116~~~
117The allowed overlap tolerance. Violations larger than ovlp are reported
118as illegal overlaps/extrusions. The default value is 1.e-1, but a thorough overlap
119check may use 1e-6
120
121(The option string is intentionally not documented here; legacy sampling modes are
122deprecated in favor of dedicated sampling entry points.)
123
124* Tuning the surface sampling
125
126The quality and cost of the surface sampling used in overlap checking can be tuned
127via TGeoManager:
128
129~~~{.cpp}
130TGeoManager::SetNsegments(Int_t nseg) (default 20)
131~~~
132Controls the segmentation used by shapes whose surface discretization depends on
133angular subdivision (e.g. tubes, cones, polycones, polygonal shapes). Increasing
134nseg increases the geometric fidelity of the discretization and usually increases
135the time spent in the point-generation and checking stages.
136
137~~~{.cpp}
138TGeoManager::SetNmeshPoints(Int_t npoints) (default 1000)
139~~~
140Controls the number of additional surface points requested via GetPointsOnSegments.
141Increasing npoints improves sampling density (potentially catching smaller overlaps)
142at the cost of more computation in the point-generation and overlap checking stages.
143
144Both nseg and npoints affect the cached mesh points. Changing them changes the
145sampling policy and triggers regeneration of cached surface points at the next
146CheckOverlaps() call.
147
148* Parallel execution
149
150When ROOT Implicit MT is enabled via:
151~~~{.cpp}
152ROOT::EnableImplicitMT(N);
153~~~
154the checker runs the final navigation-based overlap/extrusion evaluation in parallel.
155Each worker thread initializes its own navigation state to avoid shared state in
156TGeo navigation.
157*/
158
159#include "TCanvas.h"
160#include "TStyle.h"
161#include "TFile.h"
162#include "TNtuple.h"
163#include "TH2.h"
164#include "TRandom3.h"
165#include "TPolyMarker3D.h"
166#include "TPolyLine3D.h"
167#include "TStopwatch.h"
168
169#include "TGeoVoxelFinder.h"
170#include "TGeoBBox.h"
171#include "TGeoPcon.h"
172#include "TGeoTessellated.h"
173#include "TGeoManager.h"
174#include "TGeoOverlap.h"
175#include "TGeoChecker.h"
176
177#include "TBuffer3D.h"
178#include "TBuffer3DTypes.h"
179#include "TMath.h"
180
181#include <cstdlib>
182
183// statics and globals
184
185////////////////////////////////////////////////////////////////////////////////
186/// Default constructor
187
190 fGeoManager(nullptr),
191 fVsafe(nullptr),
192 fFullCheck(kFALSE),
193 fVal1(nullptr),
194 fVal2(nullptr),
195 fFlags(nullptr),
196 fTimer(nullptr),
197 fSelectedNode(nullptr),
198 fNchecks(0)
199{
200}
201
202////////////////////////////////////////////////////////////////////////////////
203/// Constructor for a given geometry
204
207 fGeoManager(geom),
208 fVsafe(nullptr),
209 fFullCheck(kFALSE),
210 fVal1(nullptr),
211 fVal2(nullptr),
212 fFlags(nullptr),
213 fTimer(nullptr),
214 fSelectedNode(nullptr),
215 fNchecks(0)
216{
217}
218
219////////////////////////////////////////////////////////////////////////////////
220/// Destructor
221
223{
224 if (fTimer)
225 delete fTimer;
226}
227
228////////////////////////////////////////////////////////////////////////////////
229/// Print current operation progress.
230
232 Bool_t refresh, const char *msg)
233{
234 static Long64_t icount = 0;
235 static TString oname;
236 static TString nname;
237 static Long64_t ocurrent = 0;
238 static Long64_t osize = 0;
239 static Int_t oseconds = 0;
240 static TStopwatch *owatch = nullptr;
241 static Bool_t oneoftwo = kFALSE;
242 static Int_t nrefresh = 0;
243 const char symbol[4] = {'=', '\\', '|', '/'};
244 char progress[11] = " ";
245 Int_t ichar = icount % 4;
246 TString message(msg);
247 message += " ";
248
249 if (!refresh) {
250 nrefresh = 0;
251 if (!size)
252 return;
253 owatch = watch;
254 oname = opname;
255 ocurrent = TMath::Abs(current);
257 if (ocurrent > osize)
258 ocurrent = osize;
259 } else {
260 nrefresh++;
261 if (!osize)
262 return;
263 }
264 icount++;
265 Double_t time = 0.;
266 Int_t hours = 0;
267 Int_t minutes = 0;
268 Int_t seconds = 0;
269 if (owatch && !last) {
270 owatch->Stop();
271 time = owatch->RealTime();
272 hours = (Int_t)(time / 3600.);
273 time -= 3600 * hours;
274 minutes = (Int_t)(time / 60.);
275 time -= 60 * minutes;
276 seconds = (Int_t)time;
277 if (refresh) {
278 if (oseconds == seconds) {
279 owatch->Continue();
280 return;
281 }
283 }
285 }
286 if (refresh && oneoftwo) {
287 nname = oname;
288 if (fNchecks <= nrefresh)
289 fNchecks = nrefresh + 1;
290 Int_t pctdone = (Int_t)(100. * nrefresh / fNchecks);
291 oname = TString::Format(" == %3d%% ==", pctdone);
292 }
293 Double_t percent = 100.0 * ocurrent / osize;
294 Int_t nchar = Int_t(percent / 10);
295 if (nchar > 10)
296 nchar = 10;
297 Int_t i;
298 for (i = 0; i < nchar; i++)
299 progress[i] = '=';
300 progress[nchar] = symbol[ichar];
301 for (i = nchar + 1; i < 10; i++)
302 progress[i] = ' ';
303 progress[10] = '\0';
304 oname += " ";
305 oname.Remove(20);
306 if (size < 10000)
307 fprintf(stderr, "%s [%10s] %4lld ", oname.Data(), progress, ocurrent);
308 else if (size < 100000)
309 fprintf(stderr, "%s [%10s] %5lld ", oname.Data(), progress, ocurrent);
310 else
311 fprintf(stderr, "%s [%10s] %7lld ", oname.Data(), progress, ocurrent);
312 if (time > 0.)
313 fprintf(stderr, "[%6.2f %%] TIME %.2d:%.2d:%.2d %s\r", percent, hours, minutes, seconds, message.Data());
314 else
315 fprintf(stderr, "[%6.2f %%] %s\r", percent, message.Data());
316 if (refresh && oneoftwo)
317 oname = nname;
318 if (owatch)
319 owatch->Continue();
320 if (last) {
321 icount = 0;
322 owatch = nullptr;
323 ocurrent = 0;
324 osize = 0;
325 oseconds = 0;
327 nrefresh = 0;
328 fprintf(stderr, "\n");
329 }
330}
331
332////////////////////////////////////////////////////////////////////////////////
333/// Check pushes and pulls needed to cross the next boundary with respect to the
334/// position given by FindNextBoundary. If radius is not mentioned the full bounding
335/// box will be sampled.
336
338{
340 Info("CheckBoundaryErrors", "Top volume is %s", tvol->GetName());
341 const TGeoShape *shape = tvol->GetShape();
342 TGeoBBox *box = (TGeoBBox *)shape;
343 Double_t dl[3];
344 Double_t ori[3];
345 Double_t xyz[3];
346 Double_t nxyz[3];
347 Double_t dir[3];
349 Char_t path[1024];
350 Char_t cdir[10];
351
352 // Tree part
353 TFile *f = new TFile("geobugs.root", "recreate");
354 TTree *bug = new TTree("bug", "Geometrical problems");
355 bug->Branch("pos", xyz, "xyz[3]/D");
356 bug->Branch("dir", dir, "dir[3]/D");
357 bug->Branch("push", &relp, "push/D");
358 bug->Branch("path", &path, "path/C");
359 bug->Branch("cdir", &cdir, "cdir/C");
360
361 dl[0] = box->GetDX();
362 dl[1] = box->GetDY();
363 dl[2] = box->GetDZ();
364 ori[0] = (box->GetOrigin())[0];
365 ori[1] = (box->GetOrigin())[1];
366 ori[2] = (box->GetOrigin())[2];
367 if (radius > 0)
368 dl[0] = dl[1] = dl[2] = radius;
369
370 TDirectory::TContext ctx{nullptr}; // Disable directory registration for histograms
371 TH1F *hnew = new TH1F("hnew", "Precision pushing", 30, -20., 10.);
372 TH1F *hold = new TH1F("hold", "Precision pulling", 30, -20., 10.);
373 TH2F *hplotS = new TH2F("hplotS", "Problematic points", 100, -dl[0], dl[0], 100, -dl[1], dl[1]);
374 gStyle->SetOptStat(111111);
375
376 TGeoNode *node = nullptr;
377 Long_t igen = 0;
378 Long_t itry = 0;
379 Long_t n100 = ntracks / 100;
380 Double_t rad = TMath::Sqrt(dl[0] * dl[0] + dl[1] * dl[1]);
381 printf("Random box : %f, %f, %f, %f, %f, %f\n", ori[0], ori[1], ori[2], dl[0], dl[1], dl[2]);
382 printf("Start... %i points\n", ntracks);
383 if (!fTimer)
384 fTimer = new TStopwatch();
385 fTimer->Reset();
386 fTimer->Start();
387 while (igen < ntracks) {
389 Double_t r = rad * gRandom->Rndm();
390 xyz[0] = ori[0] + r * TMath::Cos(phi1);
391 xyz[1] = ori[1] + r * TMath::Sin(phi1);
392 Double_t z = (1. - 2. * gRandom->Rndm());
393 xyz[2] = ori[2] + dl[2] * z * TMath::Abs(z);
394 ++itry;
396 node = fGeoManager->FindNode();
397 if (!node || node == fGeoManager->GetTopNode())
398 continue;
399 ++igen;
400 if (n100 && !(igen % n100))
401 OpProgress("Sampling progress:", igen, ntracks, fTimer);
402 Double_t cost = 1. - 2. * gRandom->Rndm();
403 Double_t sint = TMath::Sqrt((1. + cost) * (1. - cost));
404 Double_t phi = TMath::TwoPi() * gRandom->Rndm();
405 dir[0] = sint * TMath::Cos(phi);
406 dir[1] = sint * TMath::Sin(phi);
407 dir[2] = cost;
410 Double_t step = fGeoManager->GetStep();
411
412 relp = 1.e-21;
413 for (Int_t i = 0; i < 30; ++i) {
414 relp *= 10.;
415 for (Int_t j = 0; j < 3; ++j)
416 nxyz[j] = xyz[j] + step * (1. + relp) * dir[j];
417 if (!fGeoManager->IsSameLocation(nxyz[0], nxyz[1], nxyz[2])) {
418 hnew->Fill(i - 20.);
419 if (i > 15) {
421 strncpy(path, fGeoManager->GetPath(), 1024);
422 path[1023] = '\0';
423 Double_t dotp = norm[0] * dir[0] + norm[1] * dir[1] + norm[2] * dir[2];
424 printf("Forward error i=%d p=%5.4f %5.4f %5.4f s=%5.4f dot=%5.4f path=%s\n", i, xyz[0], xyz[1], xyz[2],
425 step, dotp, path);
426 hplotS->Fill(xyz[0], xyz[1], (Double_t)i);
427 strncpy(cdir, "Forward", 10);
428 bug->Fill();
429 }
430 break;
431 }
432 }
433
434 relp = -1.e-21;
435 for (Int_t i = 0; i < 30; ++i) {
436 relp *= 10.;
437 for (Int_t j = 0; j < 3; ++j)
438 nxyz[j] = xyz[j] + step * (1. + relp) * dir[j];
439 if (fGeoManager->IsSameLocation(nxyz[0], nxyz[1], nxyz[2])) {
440 hold->Fill(i - 20.);
441 if (i > 15) {
443 strncpy(path, fGeoManager->GetPath(), 1024);
444 path[1023] = '\0';
445 Double_t dotp = norm[0] * dir[0] + norm[1] * dir[1] + norm[2] * dir[2];
446 printf("Backward error i=%d p=%5.4f %5.4f %5.4f s=%5.4f dot=%5.4f path=%s\n", i, xyz[0], xyz[1], xyz[2],
447 step, dotp, path);
448 strncpy(cdir, "Backward", 10);
449 bug->Fill();
450 }
451 break;
452 }
453 }
454 }
455 fTimer->Stop();
456
457 if (itry)
458 printf("CPU time/point = %5.2emus: Real time/point = %5.2emus\n", 1000000. * fTimer->CpuTime() / itry,
459 1000000. * fTimer->RealTime() / itry);
460 bug->Write();
461 delete bug;
462 bug = nullptr;
463 delete f;
464
466
467 if (itry)
468 printf("Effic = %3.1f%%\n", (100. * igen) / itry);
469 TCanvas *c1 = new TCanvas("c1", "Results", 600, 800);
470 c1->Divide(1, 2);
471 c1->cd(1);
472 gPad->SetLogy();
473 hold->Draw();
474 c1->cd(2);
475 gPad->SetLogy();
476 hnew->Draw();
477 /*TCanvas *c3 = */ new TCanvas("c3", "Plot", 600, 600);
478 hplotS->Draw("cont0");
479}
480
481////////////////////////////////////////////////////////////////////////////////
482/// Check the boundary errors reference file created by CheckBoundaryErrors method.
483/// The shape for which the crossing failed is drawn with the starting point in red
484/// and the extrapolated point to boundary (+/- failing push/pull) in yellow.
485
487{
488 Double_t xyz[3];
489 Double_t nxyz[3];
490 Double_t dir[3];
491 Double_t lnext[3];
492 Double_t push;
493 Char_t path[1024];
494 Char_t cdir[10];
495 // Tree part
496 TFile *f = new TFile("geobugs.root", "read");
497 TTree *bug = (TTree *)f->Get("bug");
498 bug->SetBranchAddress("pos", xyz);
499 bug->SetBranchAddress("dir", dir);
500 bug->SetBranchAddress("push", &push);
501 bug->SetBranchAddress("path", &path);
502 bug->SetBranchAddress("cdir", &cdir);
503
504 Int_t nentries = (Int_t)bug->GetEntries();
505 printf("nentries %d\n", nentries);
506 if (icheck < 0) {
507 for (Int_t i = 0; i < nentries; i++) {
508 bug->GetEntry(i);
509 printf("%-9s error push=%g p=%5.4f %5.4f %5.4f s=%5.4f dot=%5.4f path=%s\n", cdir, push, xyz[0], xyz[1],
510 xyz[2], 1., 1., path);
511 }
512 } else {
513 if (icheck >= nentries)
514 return;
517 bug->GetEntry(icheck);
518 printf("%-9s error push=%g p=%5.4f %5.4f %5.4f s=%5.4f dot=%5.4f path=%s\n", cdir, push, xyz[0], xyz[1], xyz[2],
519 1., 1., path);
524 Double_t step = fGeoManager->GetStep();
525 for (Int_t j = 0; j < 3; j++)
526 nxyz[j] = xyz[j] + step * (1. + 0.1 * push) * dir[j];
528 printf("step=%g in: %s\n", step, fGeoManager->GetPath());
529 printf(" -> next = %s push=%g change=%d\n", next->GetName(), push, (UInt_t)change);
530 next->GetVolume()->InspectShape();
531 next->GetVolume()->DrawOnly();
532 if (next != fGeoManager->GetCurrentNode()) {
534 if (index1 >= 0)
536 }
539 pm->SetNextPoint(lnext[0], lnext[1], lnext[2]);
540 pm->SetMarkerStyle(2);
541 pm->SetMarkerSize(0.2);
542 pm->SetMarkerColor(kRed);
543 pm->Draw("SAME");
545 for (Int_t j = 0; j < 3; j++)
546 nxyz[j] = xyz[j] + step * dir[j];
548 pm1->SetNextPoint(lnext[0], lnext[1], lnext[2]);
549 pm1->SetMarkerStyle(2);
550 pm1->SetMarkerSize(0.2);
551 pm1->SetMarkerColor(kYellow);
552 pm1->Draw("SAME");
554 }
555 delete bug;
556 delete f;
557}
558
559////////////////////////////////////////////////////////////////////////////////
560/// Geometry checking. Optional overlap checkings (by sampling and by mesh). Optional
561/// boundary crossing check + timing per volume.
562///
563/// STAGE 1: extensive overlap checking by sampling per volume. Stdout need to be
564/// checked by user to get report, then TGeoVolume::CheckOverlaps(0.01, "s") can
565/// be called for the suspicious volumes.
566///
567/// STAGE 2: normal overlap checking using the shapes mesh - fills the list of
568/// overlaps.
569///
570/// STAGE 3: shooting NRAYS rays from VERTEX and counting the total number of
571/// crossings per volume (rays propagated from boundary to boundary until
572/// geometry exit). Timing computed and results stored in a histo.
573///
574/// STAGE 4: shooting 1 mil. random rays inside EACH volume and calling
575/// FindNextBoundary() + Safety() for each call. The timing is normalized by the
576/// number of crossings computed at stage 2 and presented as percentage.
577/// One can get a picture on which are the most "burned" volumes during
578/// transportation from geometry point of view. Another plot of the timing per
579/// volume vs. number of daughters is produced.
580///
581/// All histos are saved in the file statistics.root
582
584{
586 if (!fTimer)
587 fTimer = new TStopwatch();
588 Int_t i;
590 fFlags = new Bool_t[nuid];
591 memset(fFlags, 0, nuid * sizeof(Bool_t));
592 TGeoVolume *vol;
593 TCanvas *c = new TCanvas("overlaps", "Overlaps by sampling", 800, 800);
594
595 // STAGE 1: Overlap checking by sampling per volume
596 if (checkoverlaps) {
597 printf("====================================================================\n");
598 printf("STAGE 1: Overlap checking by sampling within 10 microns\n");
599 printf("====================================================================\n");
600 fGeoManager->CheckOverlaps(0.001, "s");
601
602 // STAGE 2: Global overlap/extrusion checking
603 printf("====================================================================\n");
604 printf("STAGE 2: Global overlap/extrusion checking within 10 microns\n");
605 printf("====================================================================\n");
607 }
608
609 if (!checkcrossings) {
610 delete[] fFlags;
611 fFlags = nullptr;
612 delete c;
613 return;
614 }
615
616 fVal1 = new Double_t[nuid];
617 fVal2 = new Double_t[nuid];
618 memset(fVal1, 0, nuid * sizeof(Double_t));
619 memset(fVal2, 0, nuid * sizeof(Double_t));
620 // STAGE 3: How many crossings per volume in a realistic case ?
621 // Ignore volumes with no daughters
622
623 // Generate rays from vertex in phi=[0,2*pi] theta=[0,pi]
624 // Int_t ntracks = 1000000;
625 printf("====================================================================\n");
626 printf("STAGE 3: Propagating %i tracks starting from vertex\n and counting number of boundary crossings...\n",
627 ntracks);
628 printf("====================================================================\n");
629 Int_t nbound = 0;
630 Double_t theta, phi;
631 Double_t point[3], dir[3];
632 memset(point, 0, 3 * sizeof(Double_t));
633 if (vertex)
634 memcpy(point, vertex, 3 * sizeof(Double_t));
635
636 fTimer->Reset();
637 fTimer->Start();
638 for (i = 0; i < ntracks; i++) {
639 phi = 2. * TMath::Pi() * gRandom->Rndm();
640 theta = TMath::ACos(1. - 2. * gRandom->Rndm());
641 dir[0] = TMath::Sin(theta) * TMath::Cos(phi);
642 dir[1] = TMath::Sin(theta) * TMath::Sin(phi);
643 dir[2] = TMath::Cos(theta);
644 if ((i % 100) == 0)
645 OpProgress("Transporting tracks", i, ntracks, fTimer);
646 // if ((i%1000)==0) printf("... remaining tracks %i\n", ntracks-i);
647 nbound += PropagateInGeom(point, dir);
648 }
649 if (!nbound) {
650 printf("No boundary crossed\n");
651 return;
652 }
653 fTimer->Stop();
654 Double_t time1 = fTimer->CpuTime() * 1.E6;
655 Double_t time2 = time1 / ntracks;
657 OpProgress("Transporting tracks", ntracks, ntracks, fTimer, kTRUE);
658 printf("Time for crossing %i boundaries: %g [ms]\n", nbound, time1);
659 printf("Time per track for full geometry traversal: %g [ms], per crossing: %g [ms]\n", time2, time3);
660
661 // STAGE 4: How much time per volume:
662
663 printf("====================================================================\n");
664 printf("STAGE 4: How much navigation time per volume per next+safety call\n");
665 printf("====================================================================\n");
667 TGeoNode *current;
668 TString path;
669 vol = fGeoManager->GetTopVolume();
670 memset(fFlags, 0, nuid * sizeof(Bool_t));
672 timer.Start();
673 i = 0;
674 char volname[30];
675 strncpy(volname, vol->GetName(), 15);
676 volname[15] = '\0';
677 OpProgress(volname, i++, nuid, &timer);
678 Score(vol, 1, TimingPerVolume(vol));
679 while ((current = next())) {
680 vol = current->GetVolume();
681 Int_t uid = vol->GetNumber();
682 if (fFlags[uid])
683 continue;
684 fFlags[uid] = kTRUE;
685 next.GetPath(path);
686 fGeoManager->cd(path.Data());
687 strncpy(volname, vol->GetName(), 15);
688 volname[15] = '\0';
689 OpProgress(volname, i++, nuid, &timer);
690 Score(vol, 1, TimingPerVolume(vol));
691 }
692 OpProgress("STAGE 4 completed", i, nuid, &timer, kTRUE);
693 // Draw some histos
695 TCanvas *c1 = new TCanvas("c2", "ncrossings", 10, 10, 900, 500);
696 c1->SetGrid();
697 c1->SetTopMargin(0.15);
698 TFile *f = new TFile("statistics.root", "RECREATE");
699 TH1F *h = new TH1F("h", "number of boundary crossings per volume", 3, 0, 3);
700 h->SetStats(false);
701 h->SetFillColor(38);
702 h->SetCanExtend(TH1::kAllAxes);
703
704 memset(fFlags, 0, nuid * sizeof(Bool_t));
705 for (i = 0; i < nuid; i++) {
706 vol = fGeoManager->GetVolume(i);
707 if (!vol->GetNdaughters())
708 continue;
709 time_tot_pertrack += fVal1[i] * fVal2[i];
710 h->Fill(vol->GetName(), (Int_t)fVal1[i]);
711 }
712 time_tot_pertrack /= ntracks;
713 h->LabelsDeflate();
714 h->LabelsOption(">", "X");
715 h->Draw();
716
717 TCanvas *c2 = new TCanvas("c3", "time spent per volume in navigation", 10, 10, 900, 500);
718 c2->SetGrid();
719 c2->SetTopMargin(0.15);
720 TH2F *h2 = new TH2F("h2", "time per FNB call vs. ndaughters", 100, 0, 100, 100, 0, 15);
721 h2->SetStats(false);
722 h2->SetMarkerStyle(2);
723 TH1F *h1 = new TH1F("h1", "percent of time spent per volume", 3, 0, 3);
724 h1->SetStats(false);
725 h1->SetFillColor(38);
727 for (i = 0; i < nuid; i++) {
728 vol = fGeoManager->GetVolume(i);
729 if (!vol || !vol->GetNdaughters())
730 continue;
731 value = fVal1[i] * fVal2[i] / ntracks / time_tot_pertrack;
732 h1->Fill(vol->GetName(), value);
733 h2->Fill(vol->GetNdaughters(), fVal2[i]);
734 }
735 h1->LabelsDeflate();
736 h1->LabelsOption(">", "X");
737 h1->Draw();
738 TCanvas *c3 = new TCanvas("c4", "timing vs. ndaughters", 10, 10, 900, 500);
739 c3->SetGrid();
740 c3->SetTopMargin(0.15);
741 h2->Draw();
742 f->Write();
743 delete[] fFlags;
744 fFlags = nullptr;
745 delete[] fVal1;
746 fVal1 = nullptr;
747 delete[] fVal2;
748 fVal2 = nullptr;
749 delete fTimer;
750 fTimer = nullptr;
751 delete c;
752}
753
754////////////////////////////////////////////////////////////////////////////////
755/// Propagate from START along DIR from boundary to boundary until exiting
756/// geometry. Fill array of hits.
757
759{
760 fGeoManager->InitTrack(start, dir);
761 TGeoNode *current = nullptr;
762 Int_t nzero = 0;
763 Int_t nhits = 0;
764 while (!fGeoManager->IsOutside()) {
765 if (nzero > 3) {
766 // Problems in trying to cross a boundary
767 printf("Error in trying to cross boundary of %s\n", current->GetName());
768 return nhits;
769 }
771 if (!current || fGeoManager->IsOutside())
772 return nhits;
773 Double_t step = fGeoManager->GetStep();
774 if (step < 2. * TGeoShape::Tolerance()) {
775 nzero++;
776 continue;
777 } else
778 nzero = 0;
779 // Generate the hit
780 nhits++;
781 TGeoVolume *vol = current->GetVolume();
782 Score(vol, 0, 1.);
783 Int_t iup = 1;
785 while (mother && mother->GetVolume()->IsAssembly()) {
786 Score(mother->GetVolume(), 0, 1.);
788 }
789 }
790 return nhits;
791}
792
793////////////////////////////////////////////////////////////////////////////////
794/// Score a hit for VOL
795
797{
798 Int_t uid = vol->GetNumber();
799 switch (ifield) {
800 case 0: fVal1[uid] += value; break;
801 case 1: fVal2[uid] += value;
802 }
803}
804
805////////////////////////////////////////////////////////////////////////////////
806/// Compute timing per "FindNextBoundary" + "Safety" call. Volume must be
807/// in the current path.
808
810{
811 fTimer->Reset();
812 const TGeoShape *shape = vol->GetShape();
813 TGeoBBox *box = (TGeoBBox *)shape;
814 Double_t dx = box->GetDX();
815 Double_t dy = box->GetDY();
816 Double_t dz = box->GetDZ();
817 Double_t ox = (box->GetOrigin())[0];
818 Double_t oy = (box->GetOrigin())[1];
819 Double_t oz = (box->GetOrigin())[2];
820 Double_t point[3], dir[3], lpt[3], ldir[3];
821 Double_t pstep = 0.;
823 Double_t theta, phi;
825 fTimer->Start();
826 for (Int_t i = 0; i < 1000000; i++) {
827 lpt[0] = ox - dx + 2 * dx * gRandom->Rndm();
828 lpt[1] = oy - dy + 2 * dy * gRandom->Rndm();
829 lpt[2] = oz - dz + 2 * dz * gRandom->Rndm();
831 fGeoManager->SetCurrentPoint(point[0], point[1], point[2]);
832 phi = 2 * TMath::Pi() * gRandom->Rndm();
833 theta = TMath::ACos(1. - 2. * gRandom->Rndm());
834 ldir[0] = TMath::Sin(theta) * TMath::Cos(phi);
835 ldir[1] = TMath::Sin(theta) * TMath::Sin(phi);
836 ldir[2] = TMath::Cos(theta);
841 // dist = TGeoShape::Big();
842 if (!vol->IsAssembly()) {
843 Bool_t inside = vol->Contains(lpt);
844 if (!inside) {
845 // dist = vol->GetShape()->DistFromOutside(lpt,ldir,3,pstep);
846 // if (dist>=pstep) continue;
847 } else {
848 vol->GetShape()->DistFromInside(lpt, ldir, 3, pstep);
849 }
850
851 if (!vol->GetNdaughters())
852 vol->GetShape()->Safety(lpt, inside);
853 }
854 if (vol->GetNdaughters()) {
857 }
858 }
859 fTimer->Stop();
861 Int_t uid = vol->GetNumber();
862 Int_t ncrossings = (Int_t)fVal1[uid];
863 if (!vol->GetNdaughters())
864 printf("Time for volume %s (shape=%s): %g [ms] ndaughters=%d ncross=%d\n", vol->GetName(),
866 else
867 printf("Time for volume %s (assemb=%d): %g [ms] ndaughters=%d ncross=%d\n", vol->GetName(), vol->IsAssembly(),
869 return time_per_track;
870}
871
872////////////////////////////////////////////////////////////////////////////////
873/// Shoot nrays with random directions from starting point (startx, starty, startz)
874/// in the reference frame of this volume. Track each ray until exiting geometry, then
875/// shoot backwards from exiting point and compare boundary crossing points.
876
878{
879 Int_t i, j;
880 Double_t start[3], end[3];
881 Double_t dir[3];
882 Double_t dummy[3];
883 Double_t eps = 0.;
884 Double_t *array1 = new Double_t[3 * 1000];
885 Double_t *array2 = new Double_t[3 * 1000];
886 TObjArray *pma = new TObjArray();
888 pm = new TPolyMarker3D();
889 pm->SetMarkerColor(2); // error > eps
890 pm->SetMarkerStyle(8);
891 pm->SetMarkerSize(0.4);
892 pma->AddAt(pm, 0);
893 pm = new TPolyMarker3D();
894 pm->SetMarkerColor(4); // point not found
895 pm->SetMarkerStyle(8);
896 pm->SetMarkerSize(0.4);
897 pma->AddAt(pm, 1);
898 pm = new TPolyMarker3D();
899 pm->SetMarkerColor(6); // extra point back
900 pm->SetMarkerStyle(8);
901 pm->SetMarkerSize(0.4);
902 pma->AddAt(pm, 2);
904 Int_t dim1 = 1000, dim2 = 1000;
905 if ((startx == 0) && (starty == 0) && (startz == 0))
906 eps = 1E-3;
907 start[0] = startx + eps;
908 start[1] = starty + eps;
909 start[2] = startz + eps;
910 Int_t n10 = nrays / 10;
911 Double_t theta, phi;
912 Double_t dw, dwmin, dx, dy, dz;
914 for (i = 0; i < nrays; i++) {
915 if (n10) {
916 if ((i % n10) == 0)
917 printf("%i percent\n", Int_t(100 * i / nrays));
918 }
919 phi = 2 * TMath::Pi() * gRandom->Rndm();
920 theta = TMath::ACos(1. - 2. * gRandom->Rndm());
921 dir[0] = TMath::Sin(theta) * TMath::Cos(phi);
922 dir[1] = TMath::Sin(theta) * TMath::Sin(phi);
923 dir[2] = TMath::Cos(theta);
924 // shoot direct ray
925 nelem1 = nelem2 = 0;
926 // printf("DIRECT %i\n", i);
927 array1 = ShootRay(&start[0], dir[0], dir[1], dir[2], array1, nelem1, dim1);
928 if (!nelem1)
929 continue;
930 // for (j=0; j<nelem1; j++) printf("%i : %f %f %f\n", j, array1[3*j], array1[3*j+1], array1[3*j+2]);
931 memcpy(&end[0], &array1[3 * (nelem1 - 1)], 3 * sizeof(Double_t));
932 // shoot ray backwards
933 // printf("BACK %i\n", i);
934 array2 = ShootRay(&end[0], -dir[0], -dir[1], -dir[2], array2, nelem2, dim2, &start[0]);
935 if (!nelem2) {
936 printf("#### NOTHING BACK ###########################\n");
937 for (j = 0; j < nelem1; j++) {
938 pm = (TPolyMarker3D *)pma->At(0);
939 pm->SetNextPoint(array1[3 * j], array1[3 * j + 1], array1[3 * j + 2]);
940 }
941 continue;
942 }
943 // printf("BACKWARDS\n");
944 Int_t k = nelem2 >> 1;
945 for (j = 0; j < k; j++) {
946 memcpy(&dummy[0], &array2[3 * j], 3 * sizeof(Double_t));
947 memcpy(&array2[3 * j], &array2[3 * (nelem2 - 1 - j)], 3 * sizeof(Double_t));
948 memcpy(&array2[3 * (nelem2 - 1 - j)], &dummy[0], 3 * sizeof(Double_t));
949 }
950 // for (j=0; j<nelem2; j++) printf("%i : %f ,%f ,%f \n", j, array2[3*j], array2[3*j+1], array2[3*j+2]);
951 if (nelem1 != nelem2)
952 printf("### DIFFERENT SIZES : nelem1=%i nelem2=%i ##########\n", nelem1, nelem2);
953 ist1 = ist2 = 0;
954 // check first match
955
956 dx = array1[3 * ist1] - array2[3 * ist2];
957 dy = array1[3 * ist1 + 1] - array2[3 * ist2 + 1];
958 dz = array1[3 * ist1 + 2] - array2[3 * ist2 + 2];
959 dw = dx * dir[0] + dy * dir[1] + dz * dir[2];
962 // printf("%i : %s (%g, %g, %g)\n", ist1, fGeoManager->GetPath(),
963 // array1[3*ist1], array1[3*ist1+1], array1[3*ist1+2]);
964 if (TMath::Abs(dw) < 1E-4) {
965 // printf(" matching %i (%g, %g, %g)\n", ist2, array2[3*ist2], array2[3*ist2+1], array2[3*ist2+2]);
966 ist2++;
967 } else {
968 printf("### NOT MATCHING %i f:(%f, %f, %f) b:(%f %f %f) DCLOSE=%f\n", ist2, array1[3 * ist1],
969 array1[3 * ist1 + 1], array1[3 * ist1 + 2], array2[3 * ist2], array2[3 * ist2 + 1],
970 array2[3 * ist2 + 2], dw);
971 pm = (TPolyMarker3D *)pma->At(0);
972 pm->SetNextPoint(array2[3 * ist2], array2[3 * ist2 + 1], array2[3 * ist2 + 2]);
973 if (dw < 0) {
974 // first boundary missed on way back
975 } else {
976 // first boundary different on way back
977 ist2++;
978 }
979 }
980
981 while ((ist1 < nelem1 - 1) && (ist2 < nelem2)) {
984 // printf("%i : %s (%g, %g, %g)\n", ist1+1, fGeoManager->GetPath(),
985 // array1[3*ist1+3], array1[3*ist1+4], array1[3*ist1+5]);
986
987 dx = array1[3 * ist1 + 3] - array1[3 * ist1];
988 dy = array1[3 * ist1 + 4] - array1[3 * ist1 + 1];
989 dz = array1[3 * ist1 + 5] - array1[3 * ist1 + 2];
990 // distance to next point
991 dwmin = dx * dir[0] + dy * dir[1] + dz * dir[2];
992 while (ist2 < nelem2) {
993 ifound = 0;
994 dx = array2[3 * ist2] - array1[3 * ist1];
995 dy = array2[3 * ist2 + 1] - array1[3 * ist1 + 1];
996 dz = array2[3 * ist2 + 2] - array1[3 * ist1 + 2];
997 dw = dx * dir[0] + dy * dir[1] + dz * dir[2];
998 if (TMath::Abs(dw - dwmin) < 1E-4) {
999 ist1++;
1000 ist2++;
1001 break;
1002 }
1003 if (dw < dwmin) {
1004 // point found on way back. Check if close enough to ist1+1
1005 ifound++;
1006 dw = dwmin - dw;
1007 if (dw < 1E-4) {
1008 // point is matching ist1+1
1009 // printf(" matching %i (%g, %g, %g) DCLOSE=%g\n", ist2, array2[3*ist2],
1010 // array2[3*ist2+1], array2[3*ist2+2], dw);
1011 ist2++;
1012 ist1++;
1013 break;
1014 } else {
1015 // extra boundary found on way back
1018 pm = (TPolyMarker3D *)pma->At(2);
1019 pm->SetNextPoint(array2[3 * ist2], array2[3 * ist2 + 1], array2[3 * ist2 + 2]);
1020 printf("### EXTRA BOUNDARY %i : %s found at DCLOSE=%f\n", ist2, fGeoManager->GetPath(), dw);
1021 ist2++;
1022 continue;
1023 }
1024 } else {
1025 if (!ifound) {
1026 // point ist1+1 not found on way back
1029 pm = (TPolyMarker3D *)pma->At(1);
1030 pm->SetNextPoint(array2[3 * ist1 + 3], array2[3 * ist1 + 4], array2[3 * ist1 + 5]);
1031 printf("### BOUNDARY MISSED BACK #########################\n");
1032 ist1++;
1033 break;
1034 } else {
1035 ist1++;
1036 break;
1037 }
1038 }
1039 }
1040 }
1041 }
1042 pm = (TPolyMarker3D *)pma->At(0);
1043 pm->Draw("SAME");
1044 pm = (TPolyMarker3D *)pma->At(1);
1045 pm->Draw("SAME");
1046 pm = (TPolyMarker3D *)pma->At(2);
1047 pm->Draw("SAME");
1048 if (gPad) {
1049 gPad->Modified();
1050 gPad->Update();
1051 }
1052 delete[] array1;
1053 delete[] array2;
1054 delete pma; // markers are drawn on the pad
1055}
1056
1057////////////////////////////////////////////////////////////////////////////////
1058/// Clean-up the mesh of pcon/pgon from useless points
1059
1061{
1062 Int_t ipoint = 0;
1063 Int_t j, k = 0;
1064 Double_t rsq;
1065 for (Int_t i = 0; i < numPoints; i++) {
1066 j = 3 * i;
1067 rsq = points[j] * points[j] + points[j + 1] * points[j + 1];
1068 if (rsq < 1.e-10)
1069 continue;
1070 points[k] = points[j];
1071 points[k + 1] = points[j + 1];
1072 points[k + 2] = points[j + 2];
1073 ipoint++;
1074 k = 3 * ipoint;
1075 }
1076 numPoints = ipoint;
1077}
1078
1079////////////////////////////////////////////////////////////////////////////////
1080/// Compute overlap/extrusion for given candidate using mesh points of the shapes.
1081
1083{
1084 out = TGeoOverlapResult{}; // reset
1085
1086 TGeoVolume *vol1 = c.fVol1;
1087 TGeoVolume *vol2 = c.fVol2;
1088 if (!vol1 || !vol2)
1089 return kFALSE;
1090
1091 // Keep legacy early outs
1092 if (vol1->IsAssembly() || vol2->IsAssembly())
1093 return kFALSE;
1094
1095 if (dynamic_cast<TGeoTessellated *>(vol1->GetShape()) || dynamic_cast<TGeoTessellated *>(vol2->GetShape()))
1096 return kFALSE;
1097
1098 TGeoShape *shape1 = vol1->GetShape();
1099 TGeoShape *shape2 = vol2->GetShape();
1100
1101 const auto &m1 = GetMeshPoints(shape1);
1102 const auto &m2 = GetMeshPoints(shape2);
1103 if (m1.fNPoints <= 0 || m2.fNPoints <= 0)
1104 return kFALSE;
1105
1106 const Double_t *points1 = m1.fPoints.data();
1107 const Double_t *points2 = m2.fPoints.data();
1108 const Int_t numPoints1 = m1.fNPoints;
1109 const Int_t numPoints2 = m2.fNPoints;
1110
1111 const TGeoHMatrix mat1 = c.fMat1;
1112 const TGeoHMatrix mat2 = c.fMat2;
1113
1115 const Double_t ovlp = c.fOvlp;
1116
1117 auto add_point = [&](const Double_t p[3]) {
1118 if (out.fPoints.size() < 100)
1119 out.fPoints.push_back({{p[0], p[1], p[2]}});
1120 };
1121
1122 auto start_result_if_needed = [&]() {
1123 if (out.fVol1)
1124 return; // already started
1125 out.fName = c.fName;
1126 out.fVol1 = vol1;
1127 out.fVol2 = vol2;
1128 out.fMat1 = mat1;
1129 out.fMat2 = mat2;
1130 out.fIsOverlap = c.fIsOverlap;
1131 out.fMaxOverlap = 0.0;
1132 };
1133
1134 // Scratch
1135 Double_t local[3], local1[3], point[3];
1137
1138 // ---------------------------
1139 // Extrusion case (c.fIsOverlap == false):
1140 // "Test vol2 extrudes vol1" and also the legacy “mother points inside daughter” pass.
1141 // ---------------------------
1142 if (!c.fIsOverlap) {
1143 Bool_t found = kFALSE;
1144
1145 // loop all points of the daughter (vol2)
1146 for (Int_t ip = 0; ip < numPoints2; ++ip) {
1147 memcpy(local, &points2[3 * ip], 3 * sizeof(Double_t));
1149 continue;
1150
1151 mat2.LocalToMaster(local, point);
1152 mat1.MasterToLocal(point, local);
1153
1154 Bool_t extrude = !shape1->Contains(local);
1155 if (extrude) {
1156 safety = shape1->Safety(local, kFALSE);
1157 if (safety < ovlp)
1158 extrude = kFALSE;
1159 }
1160
1161 if (extrude) {
1163 found = kTRUE;
1164 if (safety > out.fMaxOverlap)
1165 out.fMaxOverlap = safety;
1166 add_point(point);
1167 }
1168 }
1169
1170 // loop all points of the mother (vol1)
1171 for (Int_t ip = 0; ip < numPoints1; ++ip) {
1172 memcpy(local, &points1[3 * ip], 3 * sizeof(Double_t));
1173 if (local[0] < 1e-10 && local[1] < 1e-10)
1174 continue;
1175
1176 mat1.LocalToMaster(local, point);
1177 mat2.MasterToLocal(point, local1);
1178
1179 Bool_t extrude = shape2->Contains(local1);
1180 if (extrude) {
1181 safety = shape1->Safety(local, kTRUE);
1182 if (safety > 1E-6) {
1183 extrude = kFALSE;
1184 } else {
1185 safety = shape2->Safety(local1, kTRUE);
1186 if (safety < ovlp)
1187 extrude = kFALSE;
1188 }
1189 }
1190
1191 if (extrude) {
1193 found = kTRUE;
1194 if (safety > out.fMaxOverlap)
1195 out.fMaxOverlap = safety;
1196 add_point(point);
1197 }
1198 }
1199
1200 return found;
1201 }
1202
1203 // ---------------------------
1204 // Overlap case
1205 // ---------------------------
1206 Bool_t found = kFALSE;
1207
1208 // loop all points of first candidate (vol1) in vol2
1209 for (Int_t ip = 0; ip < numPoints1; ++ip) {
1210 memcpy(local, &points1[3 * ip], 3 * sizeof(Double_t));
1211 if (local[0] < 1e-10 && local[1] < 1e-10)
1212 continue;
1213
1214 mat1.LocalToMaster(local, point);
1215 mat2.MasterToLocal(point, local);
1216
1217 Bool_t overlap = shape2->Contains(local);
1218 if (overlap) {
1219 safety = shape2->Safety(local, kTRUE);
1220 if (safety < ovlp)
1221 overlap = kFALSE;
1222 }
1223
1224 if (overlap) {
1226 found = kTRUE;
1227 if (safety > out.fMaxOverlap)
1228 out.fMaxOverlap = safety;
1229 add_point(point);
1230 }
1231 }
1232
1233 // loop all points of second candidate (vol2) in vol1
1234 for (Int_t ip = 0; ip < numPoints2; ++ip) {
1235 memcpy(local, &points2[3 * ip], 3 * sizeof(Double_t));
1236 if (local[0] < 1e-10 && local[1] < 1e-10)
1237 continue;
1238
1239 mat2.LocalToMaster(local, point);
1240 mat1.MasterToLocal(point, local);
1241
1242 Bool_t overlap = shape1->Contains(local);
1243 if (overlap) {
1244 safety = shape1->Safety(local, kTRUE);
1245 if (safety < ovlp)
1246 overlap = kFALSE;
1247 }
1248
1249 if (overlap) {
1251 found = kTRUE;
1252 if (safety > out.fMaxOverlap)
1253 out.fMaxOverlap = safety;
1254 add_point(point);
1255 }
1256 }
1257
1258 return found;
1259}
1260
1261////////////////////////////////////////////////////////////////////////////////
1262/// Check illegal overlaps for volume VOL within a limit OVLP by sampling npoints
1263/// inside the volume shape.
1264
1266{
1267 Int_t nd = vol->GetNdaughters();
1268 if (nd < 2)
1269 return;
1271 if (!voxels)
1272 return;
1273 TGeoBBox *box = (TGeoBBox *)vol->GetShape();
1274 TGeoShape *shape;
1275 TGeoNode *node;
1276 Double_t dx = box->GetDX();
1277 Double_t dy = box->GetDY();
1278 Double_t dz = box->GetDZ();
1279 Double_t pt[3];
1280 Double_t local[3];
1281 Int_t *check_list = nullptr;
1282 Int_t ncheck = 0;
1283 const Double_t *orig = box->GetOrigin();
1284 Int_t ipoint = 0;
1285 Int_t itry = 0;
1286 Int_t iovlp = 0;
1287 Int_t id = 0, id0 = 0, id1 = 0;
1288 Bool_t in, incrt;
1289 Double_t safe;
1290 TString name1 = "";
1291 TString name2 = "";
1292 TGeoOverlap **flags = nullptr;
1293 TGeoNode *node1, *node2;
1294 Int_t novlps = 0;
1296 // Int_t tid = TGeoManager::ThreadId();
1298 TGeoStateInfo &td = *nav->GetCache()->GetInfo();
1299 while (ipoint < npoints) {
1300 // Shoot randomly in the bounding box.
1301 pt[0] = orig[0] - dx + 2. * dx * gRandom->Rndm();
1302 pt[1] = orig[1] - dy + 2. * dy * gRandom->Rndm();
1303 pt[2] = orig[2] - dz + 2. * dz * gRandom->Rndm();
1304 if (!vol->Contains(pt)) {
1305 itry++;
1306 if (itry > 10000 && !ipoint) {
1307 Error("CheckOverlapsBySampling", "No point inside volume!!! - aborting");
1308 break;
1309 }
1310 continue;
1311 }
1312 // Check if the point is inside one or more daughters
1313 in = kFALSE;
1314 ipoint++;
1315 check_list = voxels->GetCheckList(pt, ncheck, td);
1316 if (!check_list || ncheck < 2)
1317 continue;
1318 for (id = 0; id < ncheck; id++) {
1319 id0 = check_list[id];
1320 node = vol->GetNode(id0);
1321 // Ignore MANY's
1322 if (node->IsOverlapping())
1323 continue;
1324 node->GetMatrix()->MasterToLocal(pt, local);
1325 shape = node->GetVolume()->GetShape();
1326 incrt = shape->Contains(local);
1327 if (!incrt)
1328 continue;
1329 if (!in) {
1330 in = kTRUE;
1331 id1 = id0;
1332 continue;
1333 }
1334 // The point is inside 2 or more daughters, check safety
1335 safe = shape->Safety(local, kTRUE);
1336 if (safe < ovlp)
1337 continue;
1338 // We really have found an overlap -> store the point in a container
1339 iovlp++;
1340 if (!novlps) {
1341 if (flags)
1342 delete[] flags; // should never happen
1343 flags = new TGeoOverlap *[nd * nd];
1344 memset(flags, 0, nd * nd * sizeof(TGeoOverlap *));
1345 }
1346 TGeoOverlap *nodeovlp = flags[nd * id1 + id0];
1347 if (!nodeovlp) {
1348 novlps++;
1349 node1 = vol->GetNode(id1);
1350 name1 = node1->GetName();
1351 mat1 = node1->GetMatrix();
1352 Int_t cindex = node1->GetVolume()->GetCurrentNodeIndex();
1353 while (cindex >= 0) {
1354 node1 = node1->GetVolume()->GetNode(cindex);
1355 name1 += TString::Format("/%s", node1->GetName());
1356 mat1.Multiply(node1->GetMatrix());
1357 cindex = node1->GetVolume()->GetCurrentNodeIndex();
1358 }
1359 node2 = vol->GetNode(id0);
1360 name2 = node2->GetName();
1361 mat2 = node2->GetMatrix();
1362 cindex = node2->GetVolume()->GetCurrentNodeIndex();
1363 while (cindex >= 0) {
1364 node2 = node2->GetVolume()->GetNode(cindex);
1365 name2 += TString::Format("/%s", node2->GetName());
1366 mat2.Multiply(node2->GetMatrix());
1367 cindex = node2->GetVolume()->GetCurrentNodeIndex();
1368 }
1369 nodeovlp = new TGeoOverlap(
1370 TString::Format("Volume %s: node %s overlapping %s", vol->GetName(), name1.Data(), name2.Data()),
1371 node1->GetVolume(), node2->GetVolume(), &mat1, &mat2, kTRUE, safe);
1372 flags[nd * id1 + id0] = nodeovlp;
1374 }
1375 // Max 100 points per marker
1376 if (nodeovlp->GetPolyMarker()->GetN() < 100)
1377 nodeovlp->SetNextPoint(pt[0], pt[1], pt[2]);
1378 if (nodeovlp->GetOverlap() < safe)
1379 nodeovlp->SetOverlap(safe);
1380 }
1381 }
1382 nav->GetCache()->ReleaseInfo();
1383 if (flags)
1384 delete[] flags;
1385 if (!novlps)
1386 return;
1387 Double_t capacity = vol->GetShape()->Capacity();
1388 capacity *= Double_t(iovlp) / Double_t(npoints);
1389 Double_t err = 1. / TMath::Sqrt(Double_t(iovlp));
1390 Info("CheckOverlapsBySampling", "#Found %d overlaps adding-up to %g +/- %g [cm3] for daughters of %s", novlps,
1391 capacity, err * capacity, vol->GetName());
1392}
1393
1394/// @brief Materialize a TGeoOverlapResult into a TGeoOverlap
1395/// @param r The result to materialize
1397{
1398 auto *ov = new TGeoOverlap(r.fName.Data(), r.fVol1, r.fVol2, &r.fMat1, &r.fMat2, r.fIsOverlap, r.fMaxOverlap);
1399
1400 for (const auto &p : r.fPoints)
1401 ov->SetNextPoint(p[0], p[1], p[2]);
1402
1404}
1405
1406////////////////////////////////////////////////////////////////////////////////
1407/// Create a policy stamp for overlap checking
1408
1416
1417////////////////////////////////////////////////////////////////////////////////
1418/// Compute number of overlaps combinations to check per volume
1419
1421{
1422 if (vol->GetFinder())
1423 return 0;
1424 UInt_t nd = vol->GetNdaughters();
1425 if (!nd)
1426 return 0;
1427 Bool_t is_assembly = vol->IsAssembly();
1428 TGeoIterator next1(vol);
1429 TGeoIterator next2(vol);
1430 Int_t nchecks = 0;
1431 TGeoNode *node;
1432 UInt_t id;
1433 if (!is_assembly) {
1434 while ((node = next1())) {
1435 if (node->IsOverlapping()) {
1436 next1.Skip();
1437 continue;
1438 }
1439 if (!node->GetVolume()->IsAssembly()) {
1440 nchecks++;
1441 next1.Skip();
1442 }
1443 }
1444 }
1445 // now check if the daughters overlap with each other
1446 if (nd < 2)
1447 return nchecks;
1448 TGeoVoxelFinder *vox = vol->GetVoxels();
1449 if (!vox)
1450 return nchecks;
1451
1453 Int_t novlp;
1454 Int_t *ovlps;
1455 Int_t ko;
1456 UInt_t io;
1457 for (id = 0; id < nd; id++) {
1458 node01 = vol->GetNode(id);
1459 if (node01->IsOverlapping())
1460 continue;
1461 vox->FindOverlaps(id);
1462 ovlps = node01->GetOverlaps(novlp);
1463 if (!ovlps)
1464 continue;
1465 for (ko = 0; ko < novlp; ko++) { // loop all possible overlapping candidates
1466 io = ovlps[ko]; // (node1, shaped, matrix1, points, fBuff1)
1467 if (io <= id)
1468 continue;
1469 node02 = vol->GetNode(io);
1470 if (node02->IsOverlapping())
1471 continue;
1472
1473 // We have to check node against node1, but they may be assemblies
1474 if (node01->GetVolume()->IsAssembly()) {
1475 next1.Reset(node01->GetVolume());
1476 while ((node = next1())) {
1477 if (!node->GetVolume()->IsAssembly()) {
1478 if (node02->GetVolume()->IsAssembly()) {
1479 next2.Reset(node02->GetVolume());
1480 while ((node1 = next2())) {
1481 if (!node1->GetVolume()->IsAssembly()) {
1482 nchecks++;
1483 next2.Skip();
1484 }
1485 }
1486 } else {
1487 nchecks++;
1488 }
1489 next1.Skip();
1490 }
1491 }
1492 } else {
1493 // node not assembly
1494 if (node02->GetVolume()->IsAssembly()) {
1495 next2.Reset(node02->GetVolume());
1496 while ((node1 = next2())) {
1497 if (!node1->GetVolume()->IsAssembly()) {
1498 nchecks++;
1499 next2.Skip();
1500 }
1501 }
1502 } else {
1503 // node1 also not assembly
1504 nchecks++;
1505 }
1506 }
1507 }
1508 node01->SetOverlaps(nullptr, 0);
1509 }
1510 return nchecks;
1511}
1512
1514{
1516 if (!shape)
1517 return kEmpty;
1518
1519 std::shared_lock lock(fMeshCacheMutex);
1520 auto it = fMeshPointsCache.find(shape);
1521 if (it != fMeshPointsCache.end())
1522 return it->second;
1523
1524 // Strict mode: caller forgot to include this shape in BuildMeshPointsCache
1525 ::Error("TGeoChecker::GetMeshPoints",
1526 "Mesh cache miss for shape %s. BuildMeshPointsCache did not cover all candidates.", shape->ClassName());
1527 return kEmpty;
1528}
1529
1530void TGeoChecker::BuildMeshPointsCache(const std::vector<TGeoOverlapCandidate> &candidates)
1531{
1532 std::unique_lock lock(fMeshCacheMutex);
1533
1534 const auto nowStamp = CurrentMeshPolicyStamp();
1536
1537 if (policyChanged) {
1538 fMeshPointsCache.clear();
1539 fMeshPointsCache.reserve(2 * candidates.size());
1541 }
1542
1543 auto ensureShape = [&](const TGeoShape *shape) {
1544 if (!shape)
1545 return;
1546 if (fMeshPointsCache.find(shape) != fMeshPointsCache.end())
1547 return;
1549
1550 // IMPORTANT: meshN is the *only* correct size for SetPoints() buffer.
1551 Int_t meshN = 0, meshS = 0, meshP = 0;
1552 const_cast<TGeoShape *>(shape)->GetMeshNumbers(meshN, meshS, meshP);
1553
1554 // 1) Base mesh points via SetPoints (exact sizing!)
1555 if (meshN > 0) {
1556 entry.fPoints.resize(3 * meshN);
1557 const_cast<TGeoShape *>(shape)->SetPoints(entry.fPoints.data());
1558 entry.fNPoints = meshN;
1559 } else {
1560 entry.fNPoints = 0;
1561 }
1562
1563 // 2) Extra points on segments: fill into exactly-sized array, then append
1565 if (nSegWanted > 0) {
1566 std::vector<Double_t> seg(3 * nSegWanted);
1567 Bool_t usedSeg = const_cast<TGeoShape *>(shape)->GetPointsOnSegments(nSegWanted, seg.data());
1568 if (usedSeg) {
1569 const auto oldSize = entry.fPoints.size();
1570 entry.fPoints.resize(oldSize + seg.size());
1571 std::memcpy(entry.fPoints.data() + oldSize, seg.data(), seg.size() * sizeof(Double_t));
1572 entry.fNPoints += nSegWanted;
1573 }
1574 }
1575
1576 // 3) Hardening: ensure consistency between count and storage.
1577 // (No dedup; just guard against inconsistencies.)
1578 if ((Int_t)entry.fPoints.size() != 3 * entry.fNPoints) {
1579 // This should never happen with the logic above, but keep a guard.
1580 const Int_t n3 = entry.fPoints.size() / 3;
1581 entry.fNPoints = n3;
1582 entry.fPoints.resize(3 * n3);
1583 }
1584
1585 fMeshPointsCache.emplace(shape, std::move(entry));
1586 };
1587
1588 // Ensure all shapes referenced by *this* candidate set exist in the cache.
1589 for (const auto &c : candidates) {
1590 if (c.fVol1)
1591 ensureShape(c.fVol1->GetShape());
1592 if (c.fVol2)
1593 ensureShape(c.fVol2->GetShape());
1594 }
1595}
1596
1599{
1600 // Cache hit: reuse last filled content for this shape
1601 if (lastShape == shape && cachedN > 0) {
1602 points = buff.fPnts;
1603 return cachedN;
1604 }
1605
1606 // Refill: compute mesh numbers only now
1607 Int_t meshN = buff.NbPnts();
1608 Int_t meshS = buff.NbSegs();
1609 Int_t meshP = buff.NbPols();
1610 shape->GetMeshNumbers(meshN, meshS, meshP);
1611
1613 buff.SetRawSizes(nraw, 3 * nraw, 0, 0, 0, 0);
1614 points = buff.fPnts;
1615
1617
1618 Int_t filledN = 0;
1619 if (useSeg) {
1621 } else {
1622 shape->SetPoints(points);
1623 filledN = meshN;
1624 }
1625
1626 lastShape = shape;
1627 cachedN = filledN;
1628 return filledN;
1629}
1630
1631////////////////////////////////////////////////////////////////////////////////
1632/// Stage1: Enumerate all overlap candidates for volume VOL within a limit OVLP.
1633
1635 std::vector<TGeoOverlapCandidate> &out)
1636{
1637 if (vol->GetFinder())
1638 return 0;
1639 UInt_t nd = vol->GetNdaughters();
1640 if (!nd)
1641 return 0;
1642
1643 const Bool_t is_assembly = vol->IsAssembly();
1644
1645 TString opt(option);
1646 opt.ToLower();
1647 fFullCheck = opt.Contains("f");
1648
1649 Int_t ncand = 0;
1650
1651 // ---- EXTRUSIONS (only for daughters of a non-assembly volume)
1652 if (!is_assembly) {
1654 TGeoNode *node = nullptr;
1655 TGeoNode *nodecheck = nullptr;
1656 TString path;
1657 Int_t level;
1658
1659 while ((node = next1())) {
1660 if (node->IsOverlapping()) {
1661 next1.Skip();
1662 continue;
1663 }
1664 if (!node->GetVolume()->IsAssembly()) {
1665 if (fSelectedNode) {
1666 // only overlaps of the selected node OR real daughters if selected is assembly
1667 if ((fSelectedNode != node) && (!fSelectedNode->GetVolume()->IsAssembly())) {
1668 next1.Skip();
1669 continue;
1670 }
1671 if (node != fSelectedNode) {
1672 level = next1.GetLevel();
1673 while ((nodecheck = next1.GetNode(level--))) {
1674 if (nodecheck == fSelectedNode)
1675 break;
1676 }
1677 if (!nodecheck) {
1678 next1.Skip();
1679 continue;
1680 }
1681 }
1682 }
1683
1684 next1.GetPath(path);
1685 ncand++;
1686 PushCandidate(out, TString::Format("%s extruded by: %s", vol->GetName(), path.Data()), (TGeoVolume *)vol,
1687 node->GetVolume(), gGeoIdentity, next1.GetCurrentMatrix(), kFALSE, ovlp);
1688
1689 next1.Skip();
1690 }
1691 }
1692 }
1693
1694 // ---- OVERLAPS between daughters
1695 if (nd < 2)
1696 return ncand;
1697
1698 TGeoVoxelFinder *vox = vol->GetVoxels();
1699 if (!vox) {
1700 Warning("EnumerateOverlapCandidates", "Volume %s with %i daughters but not voxelized", vol->GetName(), nd);
1701 return ncand;
1702 }
1703
1706
1707 TGeoNode *node1 = nullptr;
1708 TGeoNode *node01 = nullptr;
1709 TGeoNode *node02 = nullptr;
1710 TGeoNode *nodecheck = nullptr;
1711
1713 TGeoMatrix const *tr1, *tr2;
1714 TGeoBBox const *box1, *box2;
1715 TString path, path1;
1716 UInt_t id, io;
1717 Int_t level;
1718
1719 for (id = 0; id < nd; id++) {
1720 node01 = vol->GetNode(id);
1721 if (node01->IsOverlapping())
1722 continue;
1723
1724 next1.SetTopName(node01->GetName());
1725 path = node01->GetName();
1726 //=== ANY <-> ANY ===//
1727 for (io = id + 1; io < nd; io++) {
1728 // check node01 against node02 daughters of volume
1729 node02 = vol->GetNode(io);
1730 if (node02->IsOverlapping())
1731 continue;
1732 box1 = (const TGeoBBox *)node01->GetVolume()->GetShape();
1733 tr1 = node01->GetMatrix();
1734 box2 = (const TGeoBBox *)node02->GetVolume()->GetShape();
1735 tr2 = node02->GetMatrix();
1736 // OBB check
1738 continue;
1739
1740 next2.SetTopName(node02->GetName());
1741 path1 = node02->GetName();
1742
1743 // We have to check node01 against node02, but they may be assemblies
1744 if (node01->GetVolume()->IsAssembly()) {
1745 // left node assembly - make a visitor
1746 next1.Reset(node01->GetVolume());
1747 TGeoNode *node = nullptr; // will iterate components of node01
1748 //=== ASSEMBLY/ANY <-> ANY ===//
1749 while ((node = next1())) {
1750 hmat1 = node01->GetMatrix();
1751 hmat1 *= *next1.GetCurrentMatrix();
1752 box1 = (const TGeoBBox *)node->GetVolume()->GetShape();
1753 tr1 = &hmat1;
1754 // OBB check
1756 // No intersection, skip the full left branch
1757 next1.Skip();
1758 continue;
1759 }
1760
1761 if (!node->GetVolume()->IsAssembly()) {
1762 //=== ASSEMBLY/REAL <-> ANY ===//
1763 // Current daughter of node01 is real, get its path and transformation
1764 next1.GetPath(path);
1765
1766 if (node02->GetVolume()->IsAssembly()) {
1767 next2.Reset(node02->GetVolume());
1768 //=== ASSEMBLY/REAL <-> ASSEMBLY/ANY ===//
1769 while ((node1 = next2())) {
1770 hmat2 = node02->GetMatrix();
1771 hmat2 *= *next2.GetCurrentMatrix();
1772 box2 = (const TGeoBBox *)node1->GetVolume()->GetShape();
1773 // OBB check
1775 // No intersection, skip the full right branch
1776 next2.Skip();
1777 continue;
1778 }
1779 if (!node1->GetVolume()->IsAssembly()) {
1780 //=== ASSEMBLY/REAL <-> ASSEMBLY/REAL ===//
1781 // Selected node skip logic
1782 if (fSelectedNode) {
1783 if ((fSelectedNode != node) && (fSelectedNode != node1) &&
1785 next2.Skip();
1786 continue;
1787 }
1788 if ((fSelectedNode != node1) && (fSelectedNode != node)) {
1789 level = next2.GetLevel();
1790 while ((nodecheck = next2.GetNode(level--))) {
1791 if (nodecheck == fSelectedNode)
1792 break;
1793 }
1794 if (node02 == fSelectedNode)
1795 nodecheck = node02;
1796 if (!nodecheck) {
1797 level = next1.GetLevel();
1798 while ((nodecheck = next1.GetNode(level--))) {
1799 if (nodecheck == fSelectedNode)
1800 break;
1801 }
1802 }
1803 if (node01 == fSelectedNode)
1804 nodecheck = node01;
1805 if (!nodecheck) {
1806 next2.Skip();
1807 continue;
1808 }
1809 }
1810 }
1811
1812 next2.GetPath(path1);
1813
1814 ncand++;
1815 PushCandidate(out,
1816 TString::Format("%s/%s overlapping %s/%s", vol->GetName(), path.Data(),
1817 vol->GetName(), path1.Data()),
1818 node->GetVolume(), node1->GetVolume(), &hmat1, &hmat2, kTRUE, ovlp);
1819
1820 next2.Skip();
1821 }
1822 }
1823
1824 } else {
1825 //=== ASSEMBLY/REAL <-> REAL
1826 // Selected node skip logic
1827 if (fSelectedNode) {
1828 if ((fSelectedNode != node) && (fSelectedNode != node02) &&
1830 next1.Skip();
1831 continue;
1832 }
1833 if ((fSelectedNode != node) && (fSelectedNode != node02)) {
1834 level = next1.GetLevel();
1835 while ((nodecheck = next1.GetNode(level--))) {
1836 if (nodecheck == fSelectedNode)
1837 break;
1838 }
1839 if (node01 == fSelectedNode)
1840 nodecheck = node01;
1841 if (!nodecheck) {
1842 next1.Skip();
1843 continue;
1844 }
1845 }
1846 }
1847
1848 ncand++;
1849 PushCandidate(out,
1850 TString::Format("%s/%s overlapping %s/%s", vol->GetName(), path.Data(),
1851 vol->GetName(), path1.Data()),
1852 node->GetVolume(), node02->GetVolume(), &hmat1, node02->GetMatrix(), kTRUE, ovlp);
1853 }
1854
1855 next1.Skip();
1856 }
1857 }
1858
1859 } else {
1860 if (node02->GetVolume()->IsAssembly()) {
1861 next2.Reset(node02->GetVolume());
1862 //=== REAL <-> ASSEMBLY/ANY ===//
1863 while ((node1 = next2())) {
1864 hmat2 = node02->GetMatrix();
1865 hmat2 *= *next2.GetCurrentMatrix();
1866 box2 = (const TGeoBBox *)node1->GetVolume()->GetShape();
1867 // OBB check
1868 if (!TGeoBBox::MayIntersect(box1, node01->GetMatrix(), box2, &hmat2)) {
1869 // No intersection, skip the entire right branch
1870 next2.Skip();
1871 continue;
1872 }
1873
1874 if (!node1->GetVolume()->IsAssembly()) {
1875 // Selected node skip logic
1876 if (fSelectedNode) {
1877 if ((fSelectedNode != node1) && (fSelectedNode != node01) &&
1879 next2.Skip();
1880 continue;
1881 }
1882 if ((fSelectedNode != node1) && (fSelectedNode != node01)) {
1883 level = next2.GetLevel();
1884 while ((nodecheck = next2.GetNode(level--))) {
1885 if (nodecheck == fSelectedNode)
1886 break;
1887 }
1888 if (node02 == fSelectedNode)
1889 nodecheck = node02;
1890 if (!nodecheck) {
1891 next2.Skip();
1892 continue;
1893 }
1894 }
1895 }
1896
1897 ncand++;
1898 next2.GetPath(path1);
1899 PushCandidate(out,
1900 TString::Format("%s/%s overlapping %s/%s", vol->GetName(), path.Data(),
1901 vol->GetName(), path1.Data()),
1902 node01->GetVolume(), node1->GetVolume(), node01->GetMatrix(), &hmat2, kTRUE, ovlp);
1903
1904 next2.Skip();
1905 }
1906 }
1907
1908 } else {
1909 // both not assembly
1911 continue;
1912
1913 ncand++;
1915 out,
1916 TString::Format("%s/%s overlapping %s/%s", vol->GetName(), path.Data(), vol->GetName(), path1.Data()),
1917 node01->GetVolume(), node02->GetVolume(), node01->GetMatrix(), node02->GetMatrix(), kTRUE, ovlp);
1918 }
1919 }
1920 }
1921 }
1922 return ncand;
1923}
1924
1925////////////////////////////////////////////////////////////////////////////////
1926/// Helper to fill candidates list
1927
1928void TGeoChecker::PushCandidate(std::vector<TGeoOverlapCandidate> &out, const TString &name, TGeoVolume *vol1,
1930 Double_t ovlp) const
1931{
1933 c.fName = name;
1934 c.fVol1 = vol1;
1935 c.fVol2 = vol2;
1936 c.fMat1 = TGeoHMatrix(*mat1);
1937 c.fMat2 = TGeoHMatrix(*mat2);
1938 c.fIsOverlap = isovlp;
1939 c.fOvlp = ovlp;
1940 out.emplace_back(std::move(c));
1941}
1942
1943////////////////////////////////////////////////////////////////////////////////
1944/// Print the current list of overlaps held by the manager class.
1945
1947{
1949 TGeoOverlap *ov;
1950 printf("=== Overlaps for %s ===\n", fGeoManager->GetName());
1951 while ((ov = (TGeoOverlap *)next()))
1952 ov->PrintInfo();
1953}
1954
1955////////////////////////////////////////////////////////////////////////////////
1956/// Draw point (x,y,z) over the picture of the daughters of the volume containing this point.
1957/// Generates a report regarding the path to the node containing this point and the distance to
1958/// the closest boundary.
1959
1961{
1962 Double_t point[3];
1963 Double_t local[3];
1964 point[0] = x;
1965 point[1] = y;
1966 point[2] = z;
1968 if (fVsafe) {
1969 TGeoNode *old = fVsafe->GetNode("SAFETY_1");
1970 if (old)
1971 fVsafe->GetNodes()->RemoveAt(vol->GetNdaughters() - 1);
1972 }
1973 // if (vol != fGeoManager->GetMasterVolume()) fGeoManager->RestoreMasterVolume();
1974 TGeoNode *node = fGeoManager->FindNode(point[0], point[1], point[2]);
1976 // get current node
1977 printf("=== Check current point : (%g, %g, %g) ===\n", point[0], point[1], point[2]);
1978 printf(" - path : %s\n", fGeoManager->GetPath());
1979 // get corresponding volume
1980 if (node)
1981 vol = node->GetVolume();
1982 // compute safety distance (distance to boundary ignored)
1983 Double_t close = (safety > 0.) ? safety : fGeoManager->Safety();
1984 printf("Safety radius : %f\n", close);
1985 if (close > 1E-4) {
1986 TGeoVolume *sph = fGeoManager->MakeSphere("SAFETY", vol->GetMedium(), 0, close, 0, 180, 0, 360);
1987 sph->SetLineColor(2);
1988 sph->SetLineStyle(3);
1989 vol->AddNode(sph, 1, new TGeoTranslation(local[0], local[1], local[2]));
1990 fVsafe = vol;
1991 }
1993 pm->SetMarkerColor(2);
1994 pm->SetMarkerStyle(8);
1995 pm->SetMarkerSize(0.5);
1996 pm->SetNextPoint(local[0], local[1], local[2]);
1997 if (vol->GetNdaughters() < 2)
1999 else
2002 if (!vol->IsVisible())
2003 vol->SetVisibility(kTRUE);
2004 vol->Draw();
2005 pm->Draw("SAME");
2006 gPad->Modified();
2007 gPad->Update();
2008}
2009
2010////////////////////////////////////////////////////////////////////////////////
2011/// Test for shape navigation methods. Summary for test numbers:
2012/// - 1: DistFromInside/Outside. Sample points inside the shape. Generate
2013/// directions randomly in cos(theta). Compute DistFromInside and move the
2014/// point with bigger distance. Compute DistFromOutside back from new point.
2015/// Plot d-(d1+d2)
2016/// - 2: Safety test. Sample points inside the bounding and compute safety. Generate
2017/// directions randomly in cos(theta) and compute distance to boundary. Check if
2018/// distance to boundary is bigger than safety
2019
2021{
2022 switch (testNo) {
2023 case 1: ShapeDistances(shape, nsamples, option); break;
2024 case 2: ShapeSafety(shape, nsamples, option); break;
2025 case 3: ShapeNormal(shape, nsamples, option); break;
2026 default: Error("CheckShape", "Test number %d not existent", testNo);
2027 }
2028}
2029
2030////////////////////////////////////////////////////////////////////////////////
2031/// Test TGeoShape::DistFromInside/Outside. Sample points inside the shape. Generate
2032/// directions randomly in cos(theta). Compute d1 = DistFromInside and move the
2033/// point on the boundary. Compute DistFromOutside and propagate with d2 making sure that
2034/// the shape is not re-entered. Swap direction and call DistFromOutside that
2035/// should fall back on the same point on the boundary (at d2). Propagate back on boundary
2036/// then compute DistFromInside that should be bigger than d1.
2037/// Plot d-(d1+d2)
2038
2040{
2041 Double_t dx = ((TGeoBBox *)shape)->GetDX();
2042 Double_t dy = ((TGeoBBox *)shape)->GetDY();
2043 Double_t dz = ((TGeoBBox *)shape)->GetDZ();
2044 // the box might be displaced
2045 auto origin_p = ((TGeoBBox *)shape)->GetOrigin();
2046 Double_t ox = origin_p[0];
2047 Double_t oy = origin_p[1];
2048 Double_t oz = origin_p[2];
2049
2050 Double_t dmax = 2. * TMath::Sqrt(dx * dx + dy * dy + dz * dz);
2052 Int_t itot = 0;
2053 // Number of tracks shot for every point inside the shape
2054 const Int_t kNtracks = 1000;
2055 Int_t n10 = nsamples / 10;
2056 Int_t i, j;
2057 Double_t point[3], pnew[3];
2058 Double_t dir[3], dnew[3];
2059 Double_t theta, phi, delta;
2060 TPolyMarker3D *pmfrominside = nullptr;
2061 TPolyMarker3D *pmfromoutside = nullptr;
2062 TH1D *hist = new TH1D("hTest1", "Residual distance from inside/outside", 200, -20, 0);
2063 hist->GetXaxis()->SetTitle("delta[cm] - first bin=overflow");
2064 hist->GetYaxis()->SetTitle("count");
2066
2067 if (!fTimer)
2068 fTimer = new TStopwatch();
2069 fTimer->Reset();
2070 fTimer->Start();
2071 while (itot < nsamples) {
2072 Bool_t inside = kFALSE;
2073 while (!inside) {
2074 point[0] = ox + gRandom->Uniform(-dx, dx);
2075 point[1] = oy + gRandom->Uniform(-dy, dy);
2076 point[2] = oz + gRandom->Uniform(-dz, dz);
2077 inside = shape->Contains(point);
2078 }
2079 itot++;
2080 if (n10) {
2081 if ((itot % n10) == 0)
2082 printf("%i percent\n", Int_t(100 * itot / nsamples));
2083 }
2084 for (i = 0; i < kNtracks; i++) {
2085 phi = 2 * TMath::Pi() * gRandom->Rndm();
2086 theta = TMath::ACos(1. - 2. * gRandom->Rndm());
2087 dir[0] = TMath::Sin(theta) * TMath::Cos(phi);
2088 dir[1] = TMath::Sin(theta) * TMath::Sin(phi);
2089 dir[2] = TMath::Cos(theta);
2090 dmove = dmax;
2091 // We have track direction, compute distance from inside
2092 d1 = shape->DistFromInside(point, dir, 3);
2093 if (d1 > dmove || d1 < TGeoShape::Tolerance()) {
2094 // Bad distance or bbox size, to debug
2095 new TCanvas("shape01", Form("Shape %s (%s)", shape->GetName(), shape->ClassName()), 1000, 800);
2096 shape->Draw();
2097 printf("DistFromInside: (%19.15f, %19.15f, %19.15f, %19.15f, %19.15f, %19.15f) %f/%f(max)\n", point[0],
2098 point[1], point[2], dir[0], dir[1], dir[2], d1, dmove);
2099 pmfrominside = new TPolyMarker3D(2);
2100 pmfrominside->SetMarkerColor(kRed);
2101 pmfrominside->SetMarkerStyle(24);
2102 pmfrominside->SetMarkerSize(0.4);
2103 pmfrominside->SetNextPoint(point[0], point[1], point[2]);
2104 for (j = 0; j < 3; j++)
2105 pnew[j] = point[j] + d1 * dir[j];
2106 pmfrominside->SetNextPoint(pnew[0], pnew[1], pnew[2]);
2107 pmfrominside->Draw();
2108 return;
2109 }
2110 // Propagate BEFORE the boundary and make sure that DistFromOutside
2111 // does not return 0 (!!!)
2112 // Check if there is a second crossing
2113 for (j = 0; j < 3; j++)
2114 pnew[j] = point[j] + (d1 - TGeoShape::Tolerance()) * dir[j];
2115 dnext = shape->DistFromOutside(pnew, dir, 3);
2116 if (d1 + dnext < dmax)
2117 dmove = d1 + 0.5 * dnext;
2118 // Move point and swap direction
2119 for (j = 0; j < 3; j++) {
2120 pnew[j] = point[j] + dmove * dir[j];
2121 dnew[j] = -dir[j];
2122 }
2123 // Compute now distance from outside
2124 d2 = shape->DistFromOutside(pnew, dnew, 3);
2125 delta = dmove - d1 - d2;
2126 if (TMath::Abs(delta) > 1E-6 || dnext < 2. * TGeoShape::Tolerance()) {
2127 // Error->debug this
2128 new TCanvas("shape01", Form("Shape %s (%s)", shape->GetName(), shape->ClassName()), 1000, 800);
2129 shape->Draw();
2130 printf("Error: (%19.15f, %19.15f, %19.15f, %19.15f, %19.15f, %19.15f) d1=%f d2=%f dmove=%f\n", point[0],
2131 point[1], point[2], dir[0], dir[1], dir[2], d1, d2, dmove);
2132 if (dnext < 2. * TGeoShape::Tolerance()) {
2133 printf(" (*)DistFromOutside(%19.15f, %19.15f, %19.15f, %19.15f, %19.15f, %19.15f) dnext = %f\n",
2134 point[0] + (d1 - TGeoShape::Tolerance()) * dir[0],
2135 point[1] + (d1 - TGeoShape::Tolerance()) * dir[1],
2136 point[2] + (d1 - TGeoShape::Tolerance()) * dir[2], dir[0], dir[1], dir[2], dnext);
2137 } else {
2138 printf(" DistFromOutside(%19.15f, %19.15f, %19.15f, %19.15f, %19.15f, %19.15f) dnext = %f\n",
2139 point[0] + d1 * dir[0], point[1] + d1 * dir[1], point[2] + d1 * dir[2], dir[0], dir[1], dir[2],
2140 dnext);
2141 }
2142 printf(" DistFromOutside(%19.15f, %19.15f, %19.15f, %19.15f, %19.15f, %19.15f) = %f\n", pnew[0], pnew[1],
2143 pnew[2], dnew[0], dnew[1], dnew[2], d2);
2144 pmfrominside = new TPolyMarker3D(2);
2145 pmfrominside->SetMarkerStyle(24);
2146 pmfrominside->SetMarkerSize(0.4);
2147 pmfrominside->SetMarkerColor(kRed);
2148 pmfrominside->SetNextPoint(point[0], point[1], point[2]);
2149 for (j = 0; j < 3; j++)
2150 point[j] += d1 * dir[j];
2151 pmfrominside->SetNextPoint(point[0], point[1], point[2]);
2152 pmfrominside->Draw();
2154 pmfromoutside->SetMarkerStyle(20);
2155 pmfromoutside->SetMarkerStyle(7);
2156 pmfromoutside->SetMarkerSize(0.3);
2157 pmfromoutside->SetMarkerColor(kBlue);
2158 pmfromoutside->SetNextPoint(pnew[0], pnew[1], pnew[2]);
2159 for (j = 0; j < 3; j++)
2160 pnew[j] += d2 * dnew[j];
2161 if (d2 < 1E10)
2162 pmfromoutside->SetNextPoint(pnew[0], pnew[1], pnew[2]);
2163 pmfromoutside->Draw();
2164 return;
2165 }
2166 // Compute distance from inside which should be bigger than d1
2167 for (j = 0; j < 3; j++)
2168 pnew[j] += (d2 - TGeoShape::Tolerance()) * dnew[j];
2169 dnext = shape->DistFromInside(pnew, dnew, 3);
2170 if (dnext < d1 - TGeoShape::Tolerance() || dnext > dmax) {
2171 new TCanvas("shape01", Form("Shape %s (%s)", shape->GetName(), shape->ClassName()), 1000, 800);
2172 shape->Draw();
2173 printf("Error DistFromInside(%19.15f, %19.15f, %19.15f, %19.15f, %19.15f, %19.15f) d1=%f d1p=%f\n", pnew[0],
2174 pnew[1], pnew[2], dnew[0], dnew[1], dnew[2], d1, dnext);
2175 pmfrominside = new TPolyMarker3D(2);
2176 pmfrominside->SetMarkerStyle(24);
2177 pmfrominside->SetMarkerSize(0.4);
2178 pmfrominside->SetMarkerColor(kRed);
2179 pmfrominside->SetNextPoint(point[0], point[1], point[2]);
2180 for (j = 0; j < 3; j++)
2181 point[j] += d1 * dir[j];
2182 pmfrominside->SetNextPoint(point[0], point[1], point[2]);
2183 pmfrominside->Draw();
2185 pmfromoutside->SetMarkerStyle(20);
2186 pmfromoutside->SetMarkerStyle(7);
2187 pmfromoutside->SetMarkerSize(0.3);
2188 pmfromoutside->SetMarkerColor(kBlue);
2189 pmfromoutside->SetNextPoint(pnew[0], pnew[1], pnew[2]);
2190 for (j = 0; j < 3; j++)
2191 pnew[j] += dnext * dnew[j];
2192 if (d2 < 1E10)
2193 pmfromoutside->SetNextPoint(pnew[0], pnew[1], pnew[2]);
2194 pmfromoutside->Draw();
2195 return;
2196 }
2197 if (TMath::Abs(delta) < 1E-20)
2198 delta = 1E-30;
2199 hist->Fill(TMath::Max(TMath::Log(TMath::Abs(delta)), -20.));
2200 }
2201 }
2202 fTimer->Stop();
2203 fTimer->Print();
2204 new TCanvas("Test01", "Residuals DistFromInside/Outside", 800, 600);
2205 hist->Draw();
2206}
2207
2208////////////////////////////////////////////////////////////////////////////////
2209/// Check of validity of safe distance for a given shape.
2210/// Sample points inside the 2x bounding box and compute safety. Generate
2211/// directions randomly in cos(theta) and compute distance to boundary. Check if
2212/// distance to boundary is bigger than safety.
2213
2215{
2216 Double_t dx = ((TGeoBBox *)shape)->GetDX();
2217 Double_t dy = ((TGeoBBox *)shape)->GetDY();
2218 Double_t dz = ((TGeoBBox *)shape)->GetDZ();
2219 // the box might be displaced
2220 auto origin_p = ((TGeoBBox *)shape)->GetOrigin();
2221 Double_t ox = origin_p[0];
2222 Double_t oy = origin_p[1];
2223 Double_t oz = origin_p[2];
2224
2225 // Number of tracks shot for every point inside the shape
2226 const Int_t kNtracks = 1000;
2227 Int_t n10 = nsamples / 10;
2228 Int_t i;
2229 Double_t dist;
2230 Double_t point[3];
2231 Double_t dir[3];
2232 Double_t theta, phi;
2233 TPolyMarker3D *pm1 = nullptr;
2234 TPolyMarker3D *pm2 = nullptr;
2235 if (!fTimer)
2236 fTimer = new TStopwatch();
2237 fTimer->Reset();
2238 fTimer->Start();
2239 Int_t itot = 0;
2240 while (itot < nsamples) {
2241 Bool_t inside = kFALSE;
2242 point[0] = ox + gRandom->Uniform(-2 * dx, 2 * dx);
2243 point[1] = oy + gRandom->Uniform(-2 * dy, 2 * dy);
2244 point[2] = oz + gRandom->Uniform(-2 * dz, 2 * dz);
2245 inside = shape->Contains(point);
2246 Double_t safe = shape->Safety(point, inside);
2247 itot++;
2248 if (n10) {
2249 if ((itot % n10) == 0)
2250 printf("%i percent\n", Int_t(100 * itot / nsamples));
2251 }
2252 for (i = 0; i < kNtracks; i++) {
2253 phi = 2 * TMath::Pi() * gRandom->Rndm();
2254 theta = TMath::ACos(1. - 2. * gRandom->Rndm());
2255 dir[0] = TMath::Sin(theta) * TMath::Cos(phi);
2256 dir[1] = TMath::Sin(theta) * TMath::Sin(phi);
2257 dir[2] = TMath::Cos(theta);
2258 if (inside)
2259 dist = shape->DistFromInside(point, dir, 3);
2260 else
2261 dist = shape->DistFromOutside(point, dir, 3);
2262 if (dist < safe) {
2263 printf("Error safety (%19.15f, %19.15f, %19.15f, %19.15f, %19.15f, %19.15f) safe=%f dist=%f\n", point[0],
2264 point[1], point[2], dir[0], dir[1], dir[2], safe, dist);
2265 new TCanvas("shape02", Form("Shape %s (%s)", shape->GetName(), shape->ClassName()), 1000, 800);
2266 shape->Draw();
2267 pm1 = new TPolyMarker3D(2);
2268 pm1->SetMarkerStyle(24);
2269 pm1->SetMarkerSize(0.4);
2270 pm1->SetMarkerColor(kRed);
2271 pm1->SetNextPoint(point[0], point[1], point[2]);
2272 pm1->SetNextPoint(point[0] + safe * dir[0], point[1] + safe * dir[1], point[2] + safe * dir[2]);
2273 pm1->Draw();
2274 pm2 = new TPolyMarker3D(1);
2275 pm2->SetMarkerStyle(7);
2276 pm2->SetMarkerSize(0.3);
2277 pm2->SetMarkerColor(kBlue);
2278 pm2->SetNextPoint(point[0] + dist * dir[0], point[1] + dist * dir[1], point[2] + dist * dir[2]);
2279 pm2->Draw();
2280 return;
2281 }
2282 }
2283 }
2284 fTimer->Stop();
2285 fTimer->Print();
2286}
2287
2288////////////////////////////////////////////////////////////////////////////////
2289/// Check of validity of the normal for a given shape.
2290/// Sample points inside the shape. Generate directions randomly in cos(theta)
2291/// and propagate to boundary. Compute normal and safety at crossing point, plot
2292/// the point and generate a random direction so that (dir) dot (norm) <0.
2293
2295{
2296 Double_t dx = ((TGeoBBox *)shape)->GetDX();
2297 Double_t dy = ((TGeoBBox *)shape)->GetDY();
2298 Double_t dz = ((TGeoBBox *)shape)->GetDZ();
2299 // the box might be displaced
2300 auto origin_p = ((TGeoBBox *)shape)->GetOrigin();
2301 Double_t ox = origin_p[0];
2302 Double_t oy = origin_p[1];
2303 Double_t oz = origin_p[2];
2304
2305 Double_t dmax = 2. * TMath::Sqrt(dx * dx + dy * dy + dz * dz);
2306 // Number of tracks shot for every point inside the shape
2307 const Int_t kNtracks = 1000;
2308 Int_t n10 = nsamples / 10;
2309 Int_t itot = 0, errcnt = 0, errsame = 0;
2310 Int_t i;
2311 Double_t dist, olddist, safe, dot;
2312 Double_t theta, phi, ndotd;
2313 Double_t *spoint = new Double_t[3 * nsamples];
2314 Double_t *sdir = new Double_t[3 * nsamples];
2315 while (itot < nsamples) {
2316 Bool_t inside = kFALSE;
2317 while (!inside) {
2318 spoint[3 * itot] = ox + gRandom->Uniform(-dx, dx);
2319 spoint[3 * itot + 1] = oy + gRandom->Uniform(-dy, dy);
2320 spoint[3 * itot + 2] = oz + gRandom->Uniform(-dz, dz);
2321 inside = shape->Contains(&spoint[3 * itot]);
2322 }
2323 phi = 2 * TMath::Pi() * gRandom->Rndm();
2324 theta = TMath::ACos(1. - 2. * gRandom->Rndm());
2325 sdir[3 * itot] = TMath::Sin(theta) * TMath::Cos(phi);
2326 sdir[3 * itot + 1] = TMath::Sin(theta) * TMath::Sin(phi);
2327 sdir[3 * itot + 2] = TMath::Cos(theta);
2328 itot++;
2329 }
2330 Double_t point[3], newpoint[3], oldpoint[3];
2331 Double_t dir[3], olddir[3];
2332 Double_t norm[3], newnorm[3], oldnorm[3];
2333 TCanvas *errcanvas = nullptr;
2334 TPolyMarker3D *pm1 = nullptr;
2335 TPolyMarker3D *pm2 = nullptr;
2336 pm2 = new TPolyMarker3D();
2337 // pm2->SetMarkerStyle(24);
2338 pm2->SetMarkerSize(0.2);
2339 pm2->SetMarkerColor(kBlue);
2340 if (!fTimer)
2341 fTimer = new TStopwatch();
2342 fTimer->Reset();
2343 fTimer->Start();
2344 for (itot = 0; itot < nsamples; itot++) {
2345 if (n10) {
2346 if ((itot % n10) == 0)
2347 printf("%i percent\n", Int_t(100 * itot / nsamples));
2348 }
2349 oldnorm[0] = oldnorm[1] = oldnorm[2] = 0.;
2350 olddist = 0.;
2351 for (Int_t j = 0; j < 3; j++) {
2352 oldpoint[j] = point[j] = spoint[3 * itot + j];
2353 olddir[j] = dir[j] = sdir[3 * itot + j];
2354 }
2355 for (i = 0; i < kNtracks; i++) {
2356 if (errcnt > 0)
2357 break;
2358 dist = shape->DistFromInside(point, dir, 3);
2359 if (dist > dmax) {
2360 // distance is bigger than from bounding box
2361 // should not happen for point inside
2362 printf("Error DistFromInside Too large(%19.15f, %19.15f, %19.15f, %19.15f, %19.15f, %19.15f) =%g\n",
2363 point[0], point[1], point[2], dir[0], dir[1], dir[2], dist);
2364 }
2365 for (Int_t j = 0; j < 3; j++) {
2366 newpoint[j] = point[j] + dist * dir[j];
2367 }
2368 shape->ComputeNormal(newpoint, dir, newnorm);
2369
2370 dot = olddir[0] * oldnorm[0] + olddir[1] * oldnorm[1] + olddir[2] * oldnorm[2];
2371 if (!shape->Contains(point) && shape->Safety(point, kFALSE) > 1.E-3) {
2372 errcnt++;
2373 printf("Error point outside (%19.15f, %19.15f, %19.15f, %19.15f, %19.15f, %19.15f) =%g olddist=%g\n",
2374 point[0], point[1], point[2], dir[0], dir[1], dir[2], dist, olddist);
2375 printf(" old point: (%19.15f, %19.15f, %19.15f, %19.15f, %19.15f, %19.15f)\n", oldpoint[0],
2376 oldpoint[1], oldpoint[2], olddir[0], olddir[1], olddir[2]);
2377 if (!errcanvas)
2378 errcanvas =
2379 new TCanvas("shape_err03", Form("Shape %s (%s)", shape->GetName(), shape->ClassName()), 1000, 800);
2380 if (!pm1) {
2381 pm1 = new TPolyMarker3D();
2382 pm1->SetMarkerStyle(24);
2383 pm1->SetMarkerSize(0.4);
2384 pm1->SetMarkerColor(kRed);
2385 }
2386 pm1->SetNextPoint(point[0], point[1], point[2]);
2387 pm1->SetNextPoint(oldpoint[0], oldpoint[1], oldpoint[2]);
2388 break;
2389 }
2390 if ((dist < TGeoShape::Tolerance() && olddist * dot > 1.E-3) || dist > dmax) {
2391 errsame++;
2392 if (errsame > 1) {
2393 errcnt++;
2394 printf("Error DistFromInside(%19.15f, %19.15f, %19.15f, %19.15f, %19.15f, %19.15f) =%g olddist=%g\n",
2395 point[0], point[1], point[2], dir[0], dir[1], dir[2], dist, olddist);
2396 printf(" new norm: (%g, %g, %g)\n", newnorm[0], newnorm[1], newnorm[2]);
2397 printf(" old point: (%19.15f, %19.15f, %19.15f, %19.15f, %19.15f, %19.15f)\n", oldpoint[0],
2398 oldpoint[1], oldpoint[2], olddir[0], olddir[1], olddir[2]);
2399 printf(" old norm: (%g, %g, %g)\n", oldnorm[0], oldnorm[1], oldnorm[2]);
2400 if (!errcanvas)
2401 errcanvas =
2402 new TCanvas("shape_err03", Form("Shape %s (%s)", shape->GetName(), shape->ClassName()), 1000, 800);
2403 if (!pm1) {
2404 pm1 = new TPolyMarker3D();
2405 pm1->SetMarkerStyle(24);
2406 pm1->SetMarkerSize(0.4);
2407 pm1->SetMarkerColor(kRed);
2408 }
2409 pm1->SetNextPoint(point[0], point[1], point[2]);
2410 pm1->SetNextPoint(oldpoint[0], oldpoint[1], oldpoint[2]);
2411 break;
2412 }
2413 } else
2414 errsame = 0;
2415
2416 olddist = dist;
2417 for (Int_t j = 0; j < 3; j++) {
2418 oldpoint[j] = point[j];
2419 point[j] += dist * dir[j];
2420 }
2421 safe = shape->Safety(point, kTRUE);
2422 if (safe > 1.E-3) {
2423 errcnt++;
2424 printf("Error safety (%19.15f, %19.15f, %19.15f) safe=%g\n", point[0], point[1], point[2], safe);
2425 if (!errcanvas)
2426 errcanvas =
2427 new TCanvas("shape_err03", Form("Shape %s (%s)", shape->GetName(), shape->ClassName()), 1000, 800);
2428 if (!pm1) {
2429 pm1 = new TPolyMarker3D();
2430 pm1->SetMarkerStyle(24);
2431 pm1->SetMarkerSize(0.4);
2432 pm1->SetMarkerColor(kRed);
2433 }
2434 pm1->SetNextPoint(point[0], point[1], point[2]);
2435 break;
2436 }
2437 // Compute normal
2438 shape->ComputeNormal(point, dir, norm);
2439 memcpy(oldnorm, norm, 3 * sizeof(Double_t));
2440 memcpy(olddir, dir, 3 * sizeof(Double_t));
2441 while (true) {
2442 phi = 2 * TMath::Pi() * gRandom->Rndm();
2443 theta = TMath::ACos(1. - 2. * gRandom->Rndm());
2444 dir[0] = TMath::Sin(theta) * TMath::Cos(phi);
2445 dir[1] = TMath::Sin(theta) * TMath::Sin(phi);
2446 dir[2] = TMath::Cos(theta);
2447 ndotd = dir[0] * norm[0] + dir[1] * norm[1] + dir[2] * norm[2];
2448 if (ndotd <= 0)
2449 break; // backwards, still inside shape
2450 }
2451 if ((itot % 10) == 0)
2452 pm2->SetNextPoint(point[0], point[1], point[2]);
2453 }
2454 }
2455 fTimer->Stop();
2456 fTimer->Print();
2457 if (errcanvas) {
2458 shape->Draw();
2459 pm1->Draw();
2460 }
2461
2462 new TCanvas("shape03", Form("Shape %s (%s)", shape->GetName(), shape->ClassName()), 1000, 800);
2463 pm2->Draw();
2464 delete[] spoint;
2465 delete[] sdir;
2466}
2467
2468////////////////////////////////////////////////////////////////////////////////
2469/// Generate a lego plot fot the top volume, according to option.
2470
2472 Double_t phimax, Double_t /*rmin*/, Double_t /*rmax*/, Option_t *option)
2473{
2474 TH2F *hist = new TH2F("lego", option, nphi, phimin, phimax, ntheta, themin, themax);
2475
2476 Double_t degrad = TMath::Pi() / 180.;
2477 Double_t theta, phi, step, matprop, x;
2478 Double_t start[3];
2479 Double_t dir[3];
2481 Int_t i; // loop index for phi
2482 Int_t j; // loop index for theta
2483 Int_t ntot = ntheta * nphi;
2484 Int_t n10 = ntot / 10;
2485 Int_t igen = 0, iloop = 0;
2486 printf("=== Lego plot sph. => nrays=%i\n", ntot);
2487 for (i = 1; i <= nphi; i++) {
2488 for (j = 1; j <= ntheta; j++) {
2489 igen++;
2490 if (n10) {
2491 if ((igen % n10) == 0)
2492 printf("%i percent\n", Int_t(100 * igen / ntot));
2493 }
2494 x = 0;
2495 theta = hist->GetYaxis()->GetBinCenter(j);
2496 phi = hist->GetXaxis()->GetBinCenter(i) + 1E-3;
2497 start[0] = start[1] = start[2] = 1E-3;
2498 dir[0] = TMath::Sin(theta * degrad) * TMath::Cos(phi * degrad);
2499 dir[1] = TMath::Sin(theta * degrad) * TMath::Sin(phi * degrad);
2500 dir[2] = TMath::Cos(theta * degrad);
2501 fGeoManager->InitTrack(&start[0], &dir[0]);
2503 if (fGeoManager->IsOutside())
2504 startnode = nullptr;
2505 if (startnode) {
2506 matprop = startnode->GetVolume()->GetMaterial()->GetRadLen();
2507 } else {
2508 matprop = 0.;
2509 }
2511 // fGeoManager->IsStepEntering();
2512 // find where we end-up
2514 step = fGeoManager->GetStep();
2515 while (step < 1E10) {
2516 // now see if we can make an other step
2517 iloop = 0;
2518 while (!fGeoManager->IsEntering()) {
2519 iloop++;
2520 fGeoManager->SetStep(1E-3);
2521 step += 1E-3;
2523 }
2524 if (iloop > 1000)
2525 printf("%i steps\n", iloop);
2526 if (matprop > 0) {
2527 x += step / matprop;
2528 }
2529 if (endnode == nullptr && step > 1E10)
2530 break;
2531 // generate an extra step to cross boundary
2533 if (startnode) {
2534 matprop = startnode->GetVolume()->GetMaterial()->GetRadLen();
2535 } else {
2536 matprop = 0.;
2537 }
2538
2541 step = fGeoManager->GetStep();
2542 }
2543 hist->Fill(phi, theta, x);
2544 }
2545 }
2546 return hist;
2547}
2548
2549////////////////////////////////////////////////////////////////////////////////
2550/// Draw random points in the bounding box of a volume.
2551
2553{
2554 if (!vol)
2555 return;
2556 vol->VisibleDaughters(kTRUE);
2557 vol->Draw();
2558 TString opt = option;
2559 opt.ToLower();
2560 TObjArray *pm = new TObjArray(128);
2561 TPolyMarker3D *marker = nullptr;
2562 const TGeoShape *shape = vol->GetShape();
2563 TGeoBBox *box = (TGeoBBox *)shape;
2564 Double_t dx = box->GetDX();
2565 Double_t dy = box->GetDY();
2566 Double_t dz = box->GetDZ();
2567 Double_t ox = (box->GetOrigin())[0];
2568 Double_t oy = (box->GetOrigin())[1];
2569 Double_t oz = (box->GetOrigin())[2];
2570 Double_t *xyz = new Double_t[3];
2571 printf("Random box : %f, %f, %f\n", dx, dy, dz);
2572 TGeoNode *node = nullptr;
2573 printf("Start... %i points\n", npoints);
2574 Int_t i = 0;
2575 Int_t igen = 0;
2576 Int_t ic = 0;
2577 Int_t n10 = npoints / 10;
2578 Double_t ratio = 0;
2579 while (igen < npoints) {
2580 xyz[0] = ox - dx + 2 * dx * gRandom->Rndm();
2581 xyz[1] = oy - dy + 2 * dy * gRandom->Rndm();
2582 xyz[2] = oz - dz + 2 * dz * gRandom->Rndm();
2584 igen++;
2585 if (n10) {
2586 if ((igen % n10) == 0)
2587 printf("%i percent\n", Int_t(100 * igen / npoints));
2588 }
2589 node = fGeoManager->FindNode();
2590 if (!node)
2591 continue;
2592 if (!node->IsOnScreen())
2593 continue;
2594 // draw only points in overlapping/non-overlapping volumes
2595 if (opt.Contains("many") && !node->IsOverlapping())
2596 continue;
2597 if (opt.Contains("only") && node->IsOverlapping())
2598 continue;
2599 ic = node->GetColour();
2600 if ((ic < 0) || (ic >= 128))
2601 ic = 1;
2602 marker = (TPolyMarker3D *)pm->At(ic);
2603 if (!marker) {
2604 marker = new TPolyMarker3D();
2605 marker->SetMarkerColor(ic);
2606 // marker->SetMarkerStyle(8);
2607 // marker->SetMarkerSize(0.4);
2608 pm->AddAt(marker, ic);
2609 }
2610 marker->SetNextPoint(xyz[0], xyz[1], xyz[2]);
2611 i++;
2612 }
2613 printf("Number of visible points : %i\n", i);
2614 if (igen)
2615 ratio = (Double_t)i / (Double_t)igen;
2616 printf("efficiency : %g\n", ratio);
2617 for (Int_t m = 0; m < 128; m++) {
2618 marker = (TPolyMarker3D *)pm->At(m);
2619 if (marker)
2620 marker->Draw("SAME");
2621 }
2623 printf("---Daughters of %s made invisible.\n", fGeoManager->GetTopVolume()->GetName());
2624 printf("---Make them visible with : gGeoManager->GetTopVolume()->VisibleDaughters();\n");
2625 delete pm;
2626 delete[] xyz;
2627}
2628
2629////////////////////////////////////////////////////////////////////////////////
2630/// Randomly shoot nrays from point (startx,starty,startz) and plot intersections
2631/// with surfaces for current top node.
2632
2635{
2636 TObjArray *pm = new TObjArray(128);
2638 TPolyLine3D *line = nullptr;
2639 TPolyLine3D *normline = nullptr;
2641 // vol->VisibleDaughters(kTRUE);
2642
2644 if (nrays <= 0) {
2645 nrays = 100000;
2646 random = kTRUE;
2647 }
2648 Double_t start[3];
2649 Double_t dir[3];
2650 const Double_t *point = fGeoManager->GetCurrentPoint();
2651 vol->Draw();
2652 printf("Start... %i rays\n", nrays);
2654 Bool_t vis1, vis2;
2655 Int_t i = 0;
2657 Int_t itot = 0;
2658 Int_t n10 = nrays / 10;
2659 Double_t theta, phi, step, normlen;
2660 Double_t ox = ((TGeoBBox *)vol->GetShape())->GetOrigin()[0];
2661 Double_t oy = ((TGeoBBox *)vol->GetShape())->GetOrigin()[1];
2662 Double_t oz = ((TGeoBBox *)vol->GetShape())->GetOrigin()[2];
2663 Double_t dx = ((TGeoBBox *)vol->GetShape())->GetDX();
2664 Double_t dy = ((TGeoBBox *)vol->GetShape())->GetDY();
2665 Double_t dz = ((TGeoBBox *)vol->GetShape())->GetDZ();
2666 normlen = TMath::Max(dx, dy);
2668 normlen *= 0.05;
2669 while (itot < nrays) {
2670 itot++;
2671 inull = 0;
2672 ipoint = 0;
2673 if (n10) {
2674 if ((itot % n10) == 0)
2675 printf("%i percent\n", Int_t(100 * itot / nrays));
2676 }
2677 if (random) {
2678 start[0] = ox - dx + 2 * dx * gRandom->Rndm();
2679 start[1] = oy - dy + 2 * dy * gRandom->Rndm();
2680 start[2] = oz - dz + 2 * dz * gRandom->Rndm();
2681 } else {
2682 start[0] = startx;
2683 start[1] = starty;
2684 start[2] = startz;
2685 }
2686 phi = 2 * TMath::Pi() * gRandom->Rndm();
2687 theta = TMath::ACos(1. - 2. * gRandom->Rndm());
2688 dir[0] = TMath::Sin(theta) * TMath::Cos(phi);
2689 dir[1] = TMath::Sin(theta) * TMath::Sin(phi);
2690 dir[2] = TMath::Cos(theta);
2691 startnode = fGeoManager->InitTrack(start[0], start[1], start[2], dir[0], dir[1], dir[2]);
2692 line = nullptr;
2693 if (fGeoManager->IsOutside())
2694 startnode = nullptr;
2695 vis1 = kFALSE;
2696 if (target_vol) {
2697 if (startnode && starget == startnode->GetVolume()->GetName())
2698 vis1 = kTRUE;
2699 } else {
2700 if (startnode && startnode->IsOnScreen())
2701 vis1 = kTRUE;
2702 }
2703 if (vis1) {
2704 line = new TPolyLine3D(2);
2705 line->SetLineColor(startnode->GetVolume()->GetLineColor());
2706 line->SetPoint(ipoint++, start[0], start[1], start[2]);
2707 i++;
2708 pm->Add(line);
2709 }
2711 step = fGeoManager->GetStep();
2712 if (step < TGeoShape::Tolerance())
2713 inull++;
2714 else
2715 inull = 0;
2716 if (inull > 5)
2717 break;
2718 const Double_t *normal = nullptr;
2719 if (check_norm) {
2721 if (!normal)
2722 break;
2723 }
2724 vis2 = kFALSE;
2725 if (target_vol) {
2726 if (starget == endnode->GetVolume()->GetName())
2727 vis2 = kTRUE;
2728 } else if (endnode->IsOnScreen())
2729 vis2 = kTRUE;
2730 if (ipoint > 0) {
2731 // old visible node had an entry point -> finish segment
2732 line->SetPoint(ipoint, point[0], point[1], point[2]);
2733 if (!vis2 && check_norm) {
2734 normline = new TPolyLine3D(2);
2735 normline->SetLineColor(kBlue);
2736 normline->SetLineWidth(1);
2737 normline->SetPoint(0, point[0], point[1], point[2]);
2738 normline->SetPoint(1, point[0] + normal[0] * normlen, point[1] + normal[1] * normlen,
2739 point[2] + normal[2] * normlen);
2740 pm->Add(normline);
2741 }
2742 ipoint = 0;
2743 line = nullptr;
2744 }
2745 if (vis2) {
2746 // create new segment
2747 line = new TPolyLine3D(2);
2748 line->SetLineColor(endnode->GetVolume()->GetLineColor());
2749 line->SetPoint(ipoint++, point[0], point[1], point[2]);
2750 i++;
2751 if (check_norm) {
2752 normline = new TPolyLine3D(2);
2753 normline->SetLineColor(kBlue);
2754 normline->SetLineWidth(2);
2755 normline->SetPoint(0, point[0], point[1], point[2]);
2756 normline->SetPoint(1, point[0] + normal[0] * normlen, point[1] + normal[1] * normlen,
2757 point[2] + normal[2] * normlen);
2758 }
2759 pm->Add(line);
2760 if (!random)
2761 pm->Add(normline);
2762 }
2763 }
2764 }
2765 // draw all segments
2766 for (Int_t m = 0; m < pm->GetEntriesFast(); m++) {
2767 line = (TPolyLine3D *)pm->At(m);
2768 if (line)
2769 line->Draw("SAME");
2770 }
2771 printf("number of segments : %i\n", i);
2772 // fGeoManager->GetTopVolume()->VisibleDaughters(kFALSE);
2773 // printf("---Daughters of %s made invisible.\n", fGeoManager->GetTopVolume()->GetName());
2774 // printf("---Make them visible with : gGeoManager->GetTopVolume()->VisibleDaughters();\n");
2775 delete pm;
2776}
2777
2778////////////////////////////////////////////////////////////////////////////////
2779/// shoot npoints randomly in a box of 1E-5 around current point.
2780/// return minimum distance to points outside
2781/// make sure that path to current node is updated
2782/// get the response of tgeo
2783
2785{
2786 TGeoNode *node = fGeoManager->FindNode();
2787 TGeoNode *nodegeo = nullptr;
2788 TGeoNode *nodeg3 = nullptr;
2789 TGeoNode *solg3 = nullptr;
2790 if (!node) {
2791 dist = -1;
2792 return nullptr;
2793 }
2795 if (strlen(g3path))
2796 hasg3 = kTRUE;
2798 dist = 1E10;
2799 TString common = "";
2800 // cd to common path
2801 Double_t point[3];
2802 Double_t closest[3];
2803 TGeoNode *node1 = nullptr;
2804 TGeoNode *node_close = nullptr;
2805 dist = 1E10;
2806 Double_t dist1 = 0;
2807 // initialize size of random box to epsil
2808 Double_t eps[3];
2809 eps[0] = epsil;
2810 eps[1] = epsil;
2811 eps[2] = epsil;
2813 if (hasg3) {
2815 TString name = "";
2816 Int_t index = 0;
2817 while (index >= 0) {
2818 index = spath.Index("/", index + 1);
2819 if (index > 0) {
2820 name = spath(0, index);
2821 if (strstr(g3path, name.Data())) {
2822 common = name;
2823 continue;
2824 } else
2825 break;
2826 }
2827 }
2828 // if g3 response was given, cd to common path
2829 if (strlen(common.Data())) {
2830 while (strcmp(fGeoManager->GetPath(), common.Data()) && fGeoManager->GetLevel()) {
2832 fGeoManager->CdUp();
2833 }
2836 while (strcmp(fGeoManager->GetPath(), common.Data()) && fGeoManager->GetLevel()) {
2838 fGeoManager->CdUp();
2839 }
2840 if (!nodegeo)
2841 return nullptr;
2842 if (!nodeg3)
2843 return nullptr;
2844 fGeoManager->cd(common.Data());
2846 Double_t xyz[3], local[3];
2847 for (Int_t i = 0; i < npoints; i++) {
2848 xyz[0] = point[0] - eps[0] + 2 * eps[0] * gRandom->Rndm();
2849 xyz[1] = point[1] - eps[1] + 2 * eps[1] * gRandom->Rndm();
2850 xyz[2] = point[2] - eps[2] + 2 * eps[2] * gRandom->Rndm();
2851 nodeg3->MasterToLocal(&xyz[0], &local[0]);
2852 if (!nodeg3->GetVolume()->Contains(&local[0]))
2853 continue;
2854 dist1 = TMath::Sqrt((xyz[0] - point[0]) * (xyz[0] - point[0]) + (xyz[1] - point[1]) * (xyz[1] - point[1]) +
2855 (xyz[2] - point[2]) * (xyz[2] - point[2]));
2856 if (dist1 < dist) {
2857 // save node and closest point
2858 dist = dist1;
2859 node_close = solg3;
2860 // make the random box smaller
2861 eps[0] = TMath::Abs(point[0] - pointg[0]);
2862 eps[1] = TMath::Abs(point[1] - pointg[1]);
2863 eps[2] = TMath::Abs(point[2] - pointg[2]);
2864 }
2865 }
2866 }
2867 if (!node_close)
2868 dist = -1;
2869 return node_close;
2870 }
2871
2872 // save current point
2873 memcpy(&point[0], pointg, 3 * sizeof(Double_t));
2874 for (Int_t i = 0; i < npoints; i++) {
2875 // generate a random point in MARS
2876 fGeoManager->SetCurrentPoint(point[0] - eps[0] + 2 * eps[0] * gRandom->Rndm(),
2877 point[1] - eps[1] + 2 * eps[1] * gRandom->Rndm(),
2878 point[2] - eps[2] + 2 * eps[2] * gRandom->Rndm());
2880 // check if new node1 is different from the old one
2881 if (node1 != node) {
2882 dist1 = TMath::Sqrt((point[0] - pointg[0]) * (point[0] - pointg[0]) +
2883 (point[1] - pointg[1]) * (point[1] - pointg[1]) +
2884 (point[2] - pointg[2]) * (point[2] - pointg[2]));
2885 if (dist1 < dist) {
2886 dist = dist1;
2887 node_close = node1;
2888 memcpy(&closest[0], pointg, 3 * sizeof(Double_t));
2889 // make the random box smaller
2890 eps[0] = TMath::Abs(point[0] - pointg[0]);
2891 eps[1] = TMath::Abs(point[1] - pointg[1]);
2892 eps[2] = TMath::Abs(point[2] - pointg[2]);
2893 }
2894 }
2895 }
2896 // restore the original point and path
2897 fGeoManager->FindNode(point[0], point[1], point[2]); // really needed ?
2898 if (!node_close)
2899 dist = -1;
2900 return node_close;
2901}
2902
2903////////////////////////////////////////////////////////////////////////////////
2904/// Shoot one ray from start point with direction (dirx,diry,dirz). Fills input array
2905/// with points just after boundary crossings.
2906
2908 Int_t &nelem, Int_t &dim, Double_t *endpoint) const
2909{
2910 // Int_t array_dimension = 3*dim;
2911 nelem = 0;
2912 Int_t istep = 0;
2913 if (!dim) {
2914 printf("empty input array\n");
2915 return array;
2916 }
2917 // fGeoManager->CdTop();
2918 const Double_t *point = fGeoManager->GetCurrentPoint();
2921 Double_t step, forward;
2922 Double_t dir[3];
2923 dir[0] = dirx;
2924 dir[1] = diry;
2925 dir[2] = dirz;
2926 fGeoManager->InitTrack(start, &dir[0]);
2928 // printf("Start : (%f,%f,%f)\n", point[0], point[1], point[2]);
2930 step = fGeoManager->GetStep();
2931 // printf("---next : at step=%f\n", step);
2932 if (step > 1E10)
2933 return array;
2936 while (step < 1E10) {
2937 if (endpoint) {
2938 forward = dirx * (endpoint[0] - point[0]) + diry * (endpoint[1] - point[1]) + dirz * (endpoint[2] - point[2]);
2939 if (forward < 1E-3) {
2940 // printf("exit : Passed start point. nelem=%i\n", nelem);
2941 return array;
2942 }
2943 }
2944 if (is_entering) {
2945 if (nelem >= dim) {
2946 Double_t *temparray = new Double_t[3 * (dim + 20)];
2947 memcpy(temparray, array, 3 * dim * sizeof(Double_t));
2948 delete[] array;
2949 array = temparray;
2950 dim += 20;
2951 }
2952 memcpy(&array[3 * nelem], point, 3 * sizeof(Double_t));
2953 // printf("%i (%f, %f, %f) step=%f\n", nelem, point[0], point[1], point[2], step);
2954 nelem++;
2955 } else {
2956 if (endnode == nullptr && step > 1E10) {
2957 // printf("exit : NULL endnode. nelem=%i\n", nelem);
2958 return array;
2959 }
2960 if (!fGeoManager->IsEntering()) {
2961 // if (startnode) printf("stepping %f from (%f, %f, %f) inside %s...\n", step,point[0], point[1],
2962 // point[2], startnode->GetName()); else printf("stepping %f from (%f, %f, %f) OUTSIDE...\n",
2963 // step,point[0], point[1], point[2]);
2964 istep = 0;
2965 }
2966 while (!fGeoManager->IsEntering()) {
2967 istep++;
2968 if (istep > 1E3) {
2969 // Error("ShootRay", "more than 1000 steps. Step was %f", step);
2970 nelem = 0;
2971 return array;
2972 }
2973 fGeoManager->SetStep(1E-5);
2975 }
2976 if (istep > 0)
2977 printf("%i steps\n", istep);
2978 if (nelem >= dim) {
2979 Double_t *temparray = new Double_t[3 * (dim + 20)];
2980 memcpy(temparray, array, 3 * dim * sizeof(Double_t));
2981 delete[] array;
2982 array = temparray;
2983 dim += 20;
2984 }
2985 memcpy(&array[3 * nelem], point, 3 * sizeof(Double_t));
2986 // if (endnode) printf("%i (%f, %f, %f) step=%f\n", nelem, point[0], point[1], point[2], step);
2987 nelem++;
2988 }
2990 step = fGeoManager->GetStep();
2991 // printf("---next at step=%f\n", step);
2994 }
2995 return array;
2996 // printf("exit : INFINITE step. nelem=%i\n", nelem);
2997}
2998
2999////////////////////////////////////////////////////////////////////////////////
3000/// Check time of finding "Where am I" for n points.
3001
3003{
3004 Bool_t recheck = !strcmp(option, "RECHECK");
3005 if (recheck)
3006 printf("RECHECK\n");
3007 const TGeoShape *shape = fGeoManager->GetTopVolume()->GetShape();
3008 Double_t dx = ((TGeoBBox *)shape)->GetDX();
3009 Double_t dy = ((TGeoBBox *)shape)->GetDY();
3010 Double_t dz = ((TGeoBBox *)shape)->GetDZ();
3011 Double_t ox = (((TGeoBBox *)shape)->GetOrigin())[0];
3012 Double_t oy = (((TGeoBBox *)shape)->GetOrigin())[1];
3013 Double_t oz = (((TGeoBBox *)shape)->GetOrigin())[2];
3014 Double_t *xyz = new Double_t[3 * npoints];
3015 TStopwatch *timer = new TStopwatch();
3016 printf("Random box : %f, %f, %f\n", dx, dy, dz);
3017 timer->Start(kFALSE);
3018 Int_t i;
3019 for (i = 0; i < npoints; i++) {
3020 xyz[3 * i] = ox - dx + 2 * dx * gRandom->Rndm();
3021 xyz[3 * i + 1] = oy - dy + 2 * dy * gRandom->Rndm();
3022 xyz[3 * i + 2] = oz - dz + 2 * dz * gRandom->Rndm();
3023 }
3024 timer->Stop();
3025 printf("Generation time :\n");
3026 timer->Print();
3027 timer->Reset();
3028 TGeoNode *node, *node1;
3029 printf("Start... %i points\n", npoints);
3030 timer->Start(kFALSE);
3031 for (i = 0; i < npoints; i++) {
3032 fGeoManager->SetCurrentPoint(xyz + 3 * i);
3033 if (recheck)
3034 fGeoManager->CdTop();
3035 node = fGeoManager->FindNode();
3036 if (recheck) {
3038 if (node1 != node) {
3039 printf("Difference for x=%g y=%g z=%g\n", xyz[3 * i], xyz[3 * i + 1], xyz[3 * i + 2]);
3040 printf(" from top : %s\n", node->GetName());
3041 printf(" redo : %s\n", fGeoManager->GetPath());
3042 }
3043 }
3044 }
3045 timer->Stop();
3046 timer->Print();
3047 delete[] xyz;
3048 delete timer;
3049}
3050
3051////////////////////////////////////////////////////////////////////////////////
3052/// Geometry overlap checker based on sampling.
3053
3054void TGeoChecker::TestOverlaps(const char *path)
3055{
3058 printf("Checking overlaps for path :\n");
3059 if (!fGeoManager->cd(path))
3060 return;
3061 TGeoNode *checked = fGeoManager->GetCurrentNode();
3062 checked->InspectNode();
3063 // shoot 1E4 points in the shape of the current volume
3064 Int_t npoints = 1000000;
3065 Double_t big = 1E6;
3066 Double_t xmin = big;
3067 Double_t xmax = -big;
3068 Double_t ymin = big;
3069 Double_t ymax = -big;
3070 Double_t zmin = big;
3071 Double_t zmax = -big;
3072 TObjArray *pm = new TObjArray(128);
3073 TPolyMarker3D *marker = nullptr;
3075 markthis->SetMarkerColor(5);
3076 TNtuple *ntpl = new TNtuple("ntpl", "random points", "x:y:z");
3078 Double_t *point = new Double_t[3];
3079 Double_t dx = ((TGeoBBox *)shape)->GetDX();
3080 Double_t dy = ((TGeoBBox *)shape)->GetDY();
3081 Double_t dz = ((TGeoBBox *)shape)->GetDZ();
3082 Double_t ox = (((TGeoBBox *)shape)->GetOrigin())[0];
3083 Double_t oy = (((TGeoBBox *)shape)->GetOrigin())[1];
3084 Double_t oz = (((TGeoBBox *)shape)->GetOrigin())[2];
3085 Double_t *xyz = new Double_t[3 * npoints];
3086 Int_t i = 0;
3087 printf("Generating %i points inside %s\n", npoints, fGeoManager->GetPath());
3088 while (i < npoints) {
3089 point[0] = ox - dx + 2 * dx * gRandom->Rndm();
3090 point[1] = oy - dy + 2 * dy * gRandom->Rndm();
3091 point[2] = oz - dz + 2 * dz * gRandom->Rndm();
3092 if (!shape->Contains(point))
3093 continue;
3094 // convert each point to MARS
3095 // printf("local %9.3f %9.3f %9.3f\n", point[0], point[1], point[2]);
3096 fGeoManager->LocalToMaster(point, &xyz[3 * i]);
3097 // printf("master %9.3f %9.3f %9.3f\n", xyz[3*i], xyz[3*i+1], xyz[3*i+2]);
3098 xmin = TMath::Min(xmin, xyz[3 * i]);
3099 xmax = TMath::Max(xmax, xyz[3 * i]);
3100 ymin = TMath::Min(ymin, xyz[3 * i + 1]);
3101 ymax = TMath::Max(ymax, xyz[3 * i + 1]);
3102 zmin = TMath::Min(zmin, xyz[3 * i + 2]);
3103 zmax = TMath::Max(zmax, xyz[3 * i + 2]);
3104 i++;
3105 }
3106 delete[] point;
3107 ntpl->Fill(xmin, ymin, zmin);
3108 ntpl->Fill(xmax, ymin, zmin);
3109 ntpl->Fill(xmin, ymax, zmin);
3110 ntpl->Fill(xmax, ymax, zmin);
3111 ntpl->Fill(xmin, ymin, zmax);
3112 ntpl->Fill(xmax, ymin, zmax);
3113 ntpl->Fill(xmin, ymax, zmax);
3114 ntpl->Fill(xmax, ymax, zmax);
3115 ntpl->Draw("z:y:x");
3116
3117 // shoot the poins in the geometry
3118 TGeoNode *node;
3119 TString cpath;
3120 Int_t ic = 0;
3121 TObjArray *overlaps = new TObjArray();
3122 printf("using FindNode...\n");
3123 for (Int_t j = 0; j < npoints; j++) {
3124 // always start from top level (testing only)
3125 fGeoManager->CdTop();
3126 fGeoManager->SetCurrentPoint(&xyz[3 * j]);
3127 node = fGeoManager->FindNode();
3129 if (cpath.Contains(path)) {
3130 markthis->SetNextPoint(xyz[3 * j], xyz[3 * j + 1], xyz[3 * j + 2]);
3131 continue;
3132 }
3133 // current point is found in an overlapping node
3134 if (!node)
3135 ic = 128;
3136 else
3137 ic = node->GetVolume()->GetLineColor();
3138 if (ic >= 128)
3139 ic = 0;
3140 marker = (TPolyMarker3D *)pm->At(ic);
3141 if (!marker) {
3142 marker = new TPolyMarker3D();
3143 marker->SetMarkerColor(ic);
3144 pm->AddAt(marker, ic);
3145 }
3146 // draw the overlapping point
3147 marker->SetNextPoint(xyz[3 * j], xyz[3 * j + 1], xyz[3 * j + 2]);
3148 if (node) {
3149 if (overlaps->IndexOf(node) < 0)
3150 overlaps->Add(node);
3151 }
3152 }
3153 // draw all overlapping points
3154 // for (Int_t m=0; m<128; m++) {
3155 // marker = (TPolyMarker3D*)pm->At(m);
3156 // if (marker) marker->Draw("SAME");
3157 // }
3158 markthis->Draw("SAME");
3159 if (gPad)
3160 gPad->Update();
3161 // display overlaps
3162 if (overlaps->GetEntriesFast()) {
3163 printf("list of overlapping nodes :\n");
3164 for (i = 0; i < overlaps->GetEntriesFast(); i++) {
3165 node = (TGeoNode *)overlaps->At(i);
3166 if (node->IsOverlapping())
3167 printf("%s MANY\n", node->GetName());
3168 else
3169 printf("%s ONLY\n", node->GetName());
3170 }
3171 } else
3172 printf("No overlaps\n");
3173 delete ntpl;
3174 delete pm;
3175 delete[] xyz;
3176 delete overlaps;
3177}
3178
3179////////////////////////////////////////////////////////////////////////////////
3180/// Estimate weight of top level volume with a precision SIGMA(W)/W
3181/// better than PRECISION. Option can be "v" - verbose (default).
3182
3184{
3186 Int_t nmat = matlist->GetSize();
3187 if (!nmat)
3188 return 0;
3189 Int_t *nin = new Int_t[nmat];
3190 memset(nin, 0, nmat * sizeof(Int_t));
3191 TString opt = option;
3192 opt.ToLower();
3193 Bool_t isverbose = opt.Contains("v");
3195 Double_t dx = box->GetDX();
3196 Double_t dy = box->GetDY();
3197 Double_t dz = box->GetDZ();
3198 Double_t ox = (box->GetOrigin())[0];
3199 Double_t oy = (box->GetOrigin())[1];
3200 Double_t oz = (box->GetOrigin())[2];
3201 Double_t x, y, z;
3202 TGeoNode *node;
3204 Double_t vbox = 0.000008 * dx * dy * dz; // m3
3205 Bool_t end = kFALSE;
3206 Double_t weight = 0, sigma, eps, dens;
3207 Double_t eps0 = 1.;
3208 Int_t indmat;
3209 Int_t igen = 0;
3210 Int_t iin = 0;
3211 while (!end) {
3212 x = ox - dx + 2 * dx * gRandom->Rndm();
3213 y = oy - dy + 2 * dy * gRandom->Rndm();
3214 z = oz - dz + 2 * dz * gRandom->Rndm();
3215 node = fGeoManager->FindNode(x, y, z);
3216 igen++;
3217 if (!node)
3218 continue;
3219 mat = node->GetVolume()->GetMedium()->GetMaterial();
3220 indmat = mat->GetIndex();
3221 if (indmat < 0)
3222 continue;
3223 nin[indmat]++;
3224 iin++;
3225 if ((iin % 100000) == 0 || igen > 1E8) {
3226 weight = 0;
3227 sigma = 0;
3228 for (indmat = 0; indmat < nmat; indmat++) {
3229 mat = (TGeoMaterial *)matlist->At(indmat);
3230 dens = mat->GetDensity(); // [g/cm3]
3231 if (dens < 1E-2)
3232 dens = 0;
3233 dens *= 1000.; // [kg/m3]
3234 weight += dens * Double_t(nin[indmat]);
3235 sigma += dens * dens * nin[indmat];
3236 }
3238 eps = sigma / weight;
3239 weight *= vbox / Double_t(igen);
3240 sigma *= vbox / Double_t(igen);
3242 if (isverbose) {
3243 printf("=== Weight of %s : %g +/- %g [kg]\n", fGeoManager->GetTopVolume()->GetName(), weight, sigma);
3244 }
3245 end = kTRUE;
3246 } else {
3247 if (isverbose && eps < 0.5 * eps0) {
3248 printf("%8dK: %14.7g kg %g %%\n", igen / 1000, weight, eps * 100);
3249 eps0 = eps;
3250 }
3251 }
3252 }
3253 }
3254 delete[] nin;
3255 return weight;
3256}
3257////////////////////////////////////////////////////////////////////////////////
3258/// count voxel timing
3259
3261{
3263 Double_t time;
3264 TGeoShape *shape = vol->GetShape();
3265 TGeoNode *node;
3267 Double_t *point;
3268 Double_t local[3];
3270 Int_t ncheck;
3272 TGeoStateInfo &td = *nav->GetCache()->GetInfo();
3273 timer.Start();
3274 for (Int_t i = 0; i < npoints; i++) {
3275 point = xyz + 3 * i;
3276 if (!shape->Contains(point))
3277 continue;
3278 checklist = voxels->GetCheckList(point, ncheck, td);
3279 if (!checklist)
3280 continue;
3281 if (!ncheck)
3282 continue;
3283 for (Int_t id = 0; id < ncheck; id++) {
3284 node = vol->GetNode(checklist[id]);
3285 matrix = node->GetMatrix();
3286 matrix->MasterToLocal(point, &local[0]);
3287 if (node->GetVolume()->GetShape()->Contains(&local[0]))
3288 break;
3289 }
3290 }
3291 nav->GetCache()->ReleaseInfo();
3292 time = timer.CpuTime();
3293 return time;
3294}
3295
3296////////////////////////////////////////////////////////////////////////////////
3297/// Returns optimal voxelization type for volume vol.
3298/// - kFALSE - cartesian
3299/// - kTRUE - cylindrical
3300
3302{
3303 return kFALSE;
3304}
uint32_t fFlags
#define f(i)
Definition RSha256.hxx:104
#define c(i)
Definition RSha256.hxx:101
#define h(i)
Definition RSha256.hxx:106
#define e(i)
Definition RSha256.hxx:103
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
bool Bool_t
Boolean (0=false, 1=true) (bool)
Definition RtypesCore.h:77
int Int_t
Signed integer 4 bytes (int)
Definition RtypesCore.h:59
char Char_t
Character 1 byte (char)
Definition RtypesCore.h:51
long Long_t
Signed long integer 4 bytes (long). Size depends on architecture.
Definition RtypesCore.h:68
constexpr Bool_t kFALSE
Definition RtypesCore.h:108
double Double_t
Double 8 bytes.
Definition RtypesCore.h:73
long long Long64_t
Portable signed long integer 8 bytes.
Definition RtypesCore.h:83
constexpr Bool_t kTRUE
Definition RtypesCore.h:107
const char Option_t
Option string (const char)
Definition RtypesCore.h:80
@ kRed
Definition Rtypes.h:67
@ kBlue
Definition Rtypes.h:67
@ kYellow
Definition Rtypes.h:67
@ kFullCircle
Definition TAttMarker.h:60
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t option
Option_t Option_t cindex
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t r
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t index
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize id
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t nchar
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t points
Option_t Option_t TPoint TPoint percent
char name[80]
Definition TGX11.cxx:110
R__EXTERN TGeoManager * gGeoManager
R__EXTERN TGeoIdentity * gGeoIdentity
Definition TGeoMatrix.h:538
float xmin
int nentries
float ymin
float xmax
float ymax
R__EXTERN TRandom * gRandom
Definition TRandom.h:62
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
Definition TString.cxx:2495
R__EXTERN TStyle * gStyle
Definition TStyle.h:442
#define gPad
virtual void SetFillColor(Color_t fcolor)
Set the fill area color.
Definition TAttFill.h:40
virtual Color_t GetLineColor() const
Return the line color.
Definition TAttLine.h:36
virtual void SetLineColor(Color_t lcolor)
Set the line color.
Definition TAttLine.h:44
virtual void SetMarkerColor(Color_t mcolor=1)
Set the marker color.
Definition TAttMarker.h:41
virtual void SetMarkerStyle(Style_t mstyle=1)
Set the marker style.
Definition TAttMarker.h:43
virtual Double_t GetBinCenter(Int_t bin) const
Return center of bin.
Definition TAxis.cxx:482
Generic 3D primitive description class.
Definition TBuffer3D.h:18
The Canvas class.
Definition TCanvas.h:23
TDirectory::TContext keeps track and restore the current directory.
Definition TDirectory.h:89
A ROOT file is an on-disk file, usually with extension .root, that stores objects in a file-system-li...
Definition TFile.h:130
Box class.
Definition TGeoBBox.h:18
static bool MayIntersect(const TGeoBBox *boxA, const TGeoMatrix *mA, const TGeoBBox *boxB, const TGeoMatrix *mB)
Fast "may-intersect" test for two placed TGeoBBox objects.
Definition TGeoBBox.cxx:952
Int_t FillMeshPoints(TBuffer3D &buff, const TGeoShape *shape, const TGeoShape *&lastShape, Int_t &cachedN, Int_t nMeshPoints, Double_t *&points) const
Int_t PropagateInGeom(Double_t *, Double_t *)
Propagate from START along DIR from boundary to boundary until exiting geometry.
Int_t fNchecks
! Number of checks for current volume
Definition TGeoChecker.h:66
Bool_t * fFlags
! Array of flags per volume.
Definition TGeoChecker.h:63
TStopwatch * fTimer
! Timer
Definition TGeoChecker.h:64
void CheckShape(TGeoShape *shape, Int_t testNo, Int_t nsamples, Option_t *option) override
Test for shape navigation methods.
TGeoVolume * fVsafe
Definition TGeoChecker.h:59
std::unordered_map< const TGeoShape *, MeshPointsEntry > fMeshPointsCache
! Internal map shape->mesh points
Definition TGeoChecker.h:69
TGeoChecker()
Default constructor.
void OpProgress(const char *opname, Long64_t current, Long64_t size, TStopwatch *watch=nullptr, Bool_t last=kFALSE, Bool_t refresh=kFALSE, const char *msg="") override
Print current operation progress.
TGeoNode * SamplePoints(Int_t npoints, Double_t &dist, Double_t epsil, const char *g3path) override
shoot npoints randomly in a box of 1E-5 around current point.
void CheckPoint(Double_t x=0, Double_t y=0, Double_t z=0, Option_t *option="", Double_t safety=0.) override
Draw point (x,y,z) over the picture of the daughters of the volume containing this point.
Double_t Weight(Double_t precision=0.01, Option_t *option="v") override
Estimate weight of top level volume with a precision SIGMA(W)/W better than PRECISION.
void ShapeNormal(TGeoShape *shape, Int_t nsamples, Option_t *option)
Check of validity of the normal for a given shape.
MeshPolicyStamp fMeshPolicyStamp
! policy stamp for points cache invalidation
Definition TGeoChecker.h:70
void CheckBoundaryReference(Int_t icheck=-1) override
Check the boundary errors reference file created by CheckBoundaryErrors method.
void MaterializeOverlap(const TGeoOverlapResult &r) override
Materialize a TGeoOverlapResult into a TGeoOverlap.
Double_t * fVal2
! Array of timing per volume.
Definition TGeoChecker.h:62
const MeshPointsEntry & GetMeshPoints(const TGeoShape *s) const
Bool_t TestVoxels(TGeoVolume *vol, Int_t npoints=1000000) override
Returns optimal voxelization type for volume vol.
void CheckOverlapsBySampling(const TGeoVolume *vol, Double_t ovlp=0.1, Int_t npoints=1000000) const override
Check illegal overlaps for volume VOL within a limit OVLP by sampling npoints inside the volume shape...
void BuildMeshPointsCache(const std::vector< TGeoOverlapCandidate > &candidates) override
TGeoManager * fGeoManager
Definition TGeoChecker.h:58
void ShapeDistances(TGeoShape *shape, Int_t nsamples, Option_t *option)
Test TGeoShape::DistFromInside/Outside.
Int_t NChecksPerVolume(TGeoVolume *vol)
Compute number of overlaps combinations to check per volume.
void ShapeSafety(TGeoShape *shape, Int_t nsamples, Option_t *option)
Check of validity of safe distance for a given shape.
TH2F * LegoPlot(Int_t ntheta=60, Double_t themin=0., Double_t themax=180., Int_t nphi=90, Double_t phimin=0., Double_t phimax=360., Double_t rmin=0., Double_t rmax=9999999, Option_t *option="") override
Generate a lego plot fot the top volume, according to option.
void CheckGeometry(Int_t nrays, Double_t startx, Double_t starty, Double_t startz) const override
Shoot nrays with random directions from starting point (startx, starty, startz) in the reference fram...
void Score(TGeoVolume *, Int_t, Double_t)
Score a hit for VOL.
Double_t * ShootRay(Double_t *start, Double_t dirx, Double_t diry, Double_t dirz, Double_t *array, Int_t &nelem, Int_t &dim, Double_t *enpoint=nullptr) const
Shoot one ray from start point with direction (dirx,diry,dirz).
void CleanPoints(Double_t *points, Int_t &numPoints) const
Clean-up the mesh of pcon/pgon from useless points.
bool PolicyChanged(const MeshPolicyStamp &a, const MeshPolicyStamp &b) const
Definition TGeoChecker.h:79
void PrintOverlaps() const override
Print the current list of overlaps held by the manager class.
TGeoNode * fSelectedNode
! Selected node for overlap checking
Definition TGeoChecker.h:65
void CheckGeometryFull(Bool_t checkoverlaps=kTRUE, Bool_t checkcrossings=kTRUE, Int_t nrays=10000, const Double_t *vertex=nullptr) override
Geometry checking.
void CheckBoundaryErrors(Int_t ntracks=1000000, Double_t radius=-1.) override
Check pushes and pulls needed to cross the next boundary with respect to the position given by FindNe...
~TGeoChecker() override
Destructor.
Bool_t ComputeOverlap(const TGeoOverlapCandidate &c, TGeoOverlapResult &out) const override
Compute overlap/extrusion for given candidate using mesh points of the shapes.
TGeoChecker::MeshPolicyStamp CurrentMeshPolicyStamp() const
Create a policy stamp for overlap checking.
void TestOverlaps(const char *path) override
Geometry overlap checker based on sampling.
void Test(Int_t npoints, Option_t *option) override
Check time of finding "Where am I" for n points.
std::shared_mutex fMeshCacheMutex
Definition TGeoChecker.h:68
Int_t EnumerateOverlapCandidates(const TGeoVolume *vol, Double_t ovlp, Option_t *option, std::vector< TGeoOverlapCandidate > &out) override
Stage1: Enumerate all overlap candidates for volume VOL within a limit OVLP.
Double_t TimingPerVolume(TGeoVolume *)
Compute timing per "FindNextBoundary" + "Safety" call.
void RandomRays(Int_t nrays, Double_t startx, Double_t starty, Double_t startz, const char *target_vol=nullptr, Bool_t check_norm=kFALSE) override
Randomly shoot nrays from point (startx,starty,startz) and plot intersections with surfaces for curre...
Double_t * fVal1
! Array of number of crossings per volume.
Definition TGeoChecker.h:61
Bool_t fFullCheck
Definition TGeoChecker.h:60
void RandomPoints(TGeoVolume *vol, Int_t npoints, Option_t *option) override
Draw random points in the bounding box of a volume.
Double_t CheckVoxels(TGeoVolume *vol, TGeoVoxelFinder *voxels, Double_t *xyz, Int_t npoints)
count voxel timing
void PushCandidate(std::vector< TGeoOverlapCandidate > &out, const TString &name, TGeoVolume *vol1, TGeoVolume *vol2, const TGeoMatrix *mat1, const TGeoMatrix *mat2, Bool_t isovlp, Double_t ovlp) const
Helper to fill candidates list.
Matrix class used for computing global transformations Should NOT be used for node definition.
Definition TGeoMatrix.h:459
A geometry iterator.
Definition TGeoNode.h:249
void GetPath(TString &path) const
Returns the path for the current node.
The manager class for any TGeo geometry.
Definition TGeoManager.h:46
TGeoNode * GetMother(Int_t up=1) const
Double_t * FindNormalFast()
Computes fast normal to next crossed boundary, assuming that the current point is close enough to the...
TObjArray * GetListOfUVolumes() const
TObjArray * GetListOfOverlaps()
void CdUp()
Go one level up in geometry.
virtual Bool_t cd(const char *path="")
Browse the tree of nodes starting from fTopNode according to pathname.
void LocalToMaster(const Double_t *local, Double_t *master) const
void RestoreMasterVolume()
Restore the master volume of the geometry.
TGeoNode * FindNextDaughterBoundary(Double_t *point, Double_t *dir, Int_t &idaughter, Bool_t compmatrix=kFALSE)
Computes as fStep the distance to next daughter of the current volume.
TGeoNavigator * GetCurrentNavigator() const
Returns current navigator for the calling thread.
TGeoVolume * GetMasterVolume() const
TGeoNode * GetCurrentNode() const
void SetCurrentDirection(Double_t *dir)
void SetVisLevel(Int_t level=3)
set default level down to which visualization is performed
TGeoNode * FindNextBoundary(Double_t stepmax=TGeoShape::Big(), const char *path="", Bool_t frombdr=kFALSE)
Find distance to next boundary and store it in fStep.
TGeoNode * Step(Bool_t is_geom=kTRUE, Bool_t cross=kTRUE)
Make a rectilinear step of length fStep from current point (fPoint) on current direction (fDirection)...
TGeoVolume * GetVolume(const char *name) const
Search for a named volume. All trailing blanks stripped.
TGeoNode * FindNextBoundaryAndStep(Double_t stepmax=TGeoShape::Big(), Bool_t compsafe=kFALSE)
Compute distance to next boundary within STEPMAX.
void SetCurrentPoint(Double_t *point)
Double_t * FindNormal(Bool_t forward=kTRUE)
Computes normal vector to the next surface that will be or was already crossed when propagating on a ...
TGeoNode * FindNode(Bool_t safe_start=kTRUE)
Returns deepest node containing current point.
const Double_t * GetCurrentPoint() const
TGeoVolume * MakeSphere(const char *name, TGeoMedium *medium, Double_t rmin, Double_t rmax, Double_t themin=0, Double_t themax=180, Double_t phimin=0, Double_t phimax=360)
Make in one step a volume pointing to a sphere shape with given medium.
Bool_t IsOutside() const
TGeoNode * InitTrack(const Double_t *point, const Double_t *dir)
Initialize current point and current direction vector (normalized) in MARS.
Int_t GetLevel() const
Double_t GetStep() const
TGeoHMatrix * GetCurrentMatrix() const
TGeoNode * GetTopNode() const
Bool_t IsSameLocation(Double_t x, Double_t y, Double_t z, Bool_t change=kFALSE)
Checks if point (x,y,z) is still in the current node.
const char * GetPath() const
Get path to the current node in the form /node0/node1/...
Int_t AddOverlap(const TNamed *ovlp)
Add an illegal overlap/extrusion to the list.
static void SetVerboseLevel(Int_t vl)
Return current verbosity level (static function).
void SetStep(Double_t step)
TGeoVolume * GetCurrentVolume() const
static Int_t GetVerboseLevel()
Set verbosity level (static function).
void CdTop()
Make top level node the current node.
Double_t Safety(Bool_t inside=kFALSE)
Compute safe distance from the current point.
void MasterToLocal(const Double_t *master, Double_t *local) const
void ResetState()
Reset current state flags.
void CdDown(Int_t index)
Make a daughter of current node current.
TList * GetListOfMaterials() const
Int_t GetNsegments() const
Get number of segments approximating circles.
TGeoVolume * GetTopVolume() const
void SetTopVisible(Bool_t vis=kTRUE)
make top volume visible on screen
void CheckOverlaps(Double_t ovlp=0.1, Option_t *option="")
Check all geometry for illegal overlaps within a limit OVLP.
Bool_t IsEntering() const
Base class describing materials.
Geometrical transformation package.
Definition TGeoMatrix.h:39
virtual void LocalToMasterVect(const Double_t *local, Double_t *master) const
convert a vector by multiplying its column vector (x, y, z, 1) to matrix inverse
virtual void LocalToMaster(const Double_t *local, Double_t *master) const
convert a point by multiplying its column vector (x, y, z, 1) to matrix inverse
TGeoMaterial * GetMaterial() const
Definition TGeoMedium.h:49
Class providing navigation API for TGeo geometries.
A node represent a volume positioned inside another.They store links to both volumes and to the TGeoM...
Definition TGeoNode.h:39
Bool_t IsOverlapping() const
Definition TGeoNode.h:108
Bool_t IsOnScreen() const
check if this node is drawn. Assumes that this node is current
Definition TGeoNode.cxx:422
TGeoVolume * GetVolume() const
Definition TGeoNode.h:100
virtual TGeoMatrix * GetMatrix() const =0
Int_t GetColour() const
Definition TGeoNode.h:87
void InspectNode() const
Inspect this node.
Definition TGeoNode.cxx:432
Base class describing geometry overlaps.
Definition TGeoOverlap.h:37
Base abstract class for all shapes.
Definition TGeoShape.h:25
static Double_t Big()
Definition TGeoShape.h:95
virtual Double_t DistFromInside(const Double_t *point, const Double_t *dir, Int_t iact=1, Double_t step=TGeoShape::Big(), Double_t *safe=nullptr) const =0
virtual void GetMeshNumbers(Int_t &, Int_t &, Int_t &) const
Definition TGeoShape.h:133
virtual Bool_t GetPointsOnSegments(Int_t npoints, Double_t *array) const =0
void Draw(Option_t *option="") override
Draw this shape.
virtual Double_t Safety(const Double_t *point, Bool_t in=kTRUE) const =0
virtual void ComputeNormal(const Double_t *point, const Double_t *dir, Double_t *norm) const =0
virtual Double_t DistFromOutside(const Double_t *point, const Double_t *dir, Int_t iact=1, Double_t step=TGeoShape::Big(), Double_t *safe=nullptr) const =0
const char * GetName() const override
Get the shape name.
virtual Double_t Capacity() const =0
virtual Bool_t Contains(const Double_t *point) const =0
static Double_t Tolerance()
Definition TGeoShape.h:98
virtual void SetPoints(Double_t *points) const =0
Tessellated solid class.
Class describing translations.
Definition TGeoMatrix.h:117
TGeoVolume, TGeoVolumeMulti, TGeoVolumeAssembly are the volume classes.
Definition TGeoVolume.h:43
void SetVisibility(Bool_t vis=kTRUE) override
set visibility of this volume
TGeoMedium * GetMedium() const
Definition TGeoVolume.h:176
Bool_t Contains(const Double_t *point) const
Definition TGeoVolume.h:105
virtual TGeoNode * AddNode(TGeoVolume *vol, Int_t copy_no, TGeoMatrix *mat=nullptr, Option_t *option="")
Add a TGeoNode to the list of nodes.
void Draw(Option_t *option="") override
draw top volume according to option
Int_t GetNdaughters() const
Definition TGeoVolume.h:363
TObjArray * GetNodes()
Definition TGeoVolume.h:170
void VisibleDaughters(Bool_t vis=kTRUE)
set visibility for daughters
TGeoNode * GetNode(const char *name) const
get the pointer to a daughter node
Int_t GetIndex(const TGeoNode *node) const
get index number for a given daughter
TGeoPatternFinder * GetFinder() const
Definition TGeoVolume.h:178
TGeoVoxelFinder * GetVoxels() const
Getter for optimization structure.
Int_t GetNumber() const
Definition TGeoVolume.h:185
TGeoShape * GetShape() const
Definition TGeoVolume.h:191
virtual void DrawOnly(Option_t *option="")
draw only this volume
virtual Bool_t IsAssembly() const
Returns true if the volume is an assembly or a scaled assembly.
virtual Bool_t IsVisible() const
Definition TGeoVolume.h:156
void InspectShape() const
Definition TGeoVolume.h:196
Finder class handling voxels.
1-D histogram with a double per channel (see TH1 documentation)
Definition TH1.h:926
1-D histogram with a float per channel (see TH1 documentation)
Definition TH1.h:878
@ kAllAxes
Definition TH1.h:126
virtual void LabelsOption(Option_t *option="h", Option_t *axis="X")
Sort bins with labels or set option(s) to draw axis with labels.
Definition TH1.cxx:5443
TAxis * GetXaxis()
Definition TH1.h:571
virtual Int_t Fill(Double_t x)
Increment bin with abscissa X by 1.
Definition TH1.cxx:3372
TAxis * GetYaxis()
Definition TH1.h:572
void Draw(Option_t *option="") override
Draw this histogram with options.
Definition TH1.cxx:3076
virtual UInt_t SetCanExtend(UInt_t extendBitMask)
Make the histogram axes extendable / not extendable according to the bit mask returns the previous bi...
Definition TH1.cxx:6743
virtual void LabelsDeflate(Option_t *axis="X")
Reduce the number of bins for the axis passed in the option to the number of bins having a label.
Definition TH1.cxx:5306
virtual void SetStats(Bool_t stats=kTRUE)
Set statistics option on/off.
Definition TH1.cxx:9106
2-D histogram with a float per channel (see TH1 documentation)
Definition TH2.h:345
Int_t Fill(Double_t) override
Invalid Fill method.
Definition TH2.cxx:363
A doubly linked list.
Definition TList.h:38
virtual void SetTitle(const char *title="")
Set the title of the TNamed.
Definition TNamed.cxx:173
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
A simple TTree restricted to a list of float variables only.
Definition TNtuple.h:28
An array of TObjects.
Definition TObjArray.h:31
Int_t GetEntriesFast() const
Definition TObjArray.h:58
Int_t IndexOf(const TObject *obj) const override
Int_t GetEntries() const override
Return the number of objects in array (i.e.
TObject * At(Int_t idx) const override
Definition TObjArray.h:170
TObject * RemoveAt(Int_t idx) override
Remove object at index idx.
void Add(TObject *obj) override
Definition TObjArray.h:68
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition TObject.cxx:224
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition TObject.cxx:1081
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1095
virtual void Draw(Option_t *option="")
Default Draw method for all objects.
Definition TObject.cxx:290
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition TObject.cxx:1069
A 3-dimensional polyline.
Definition TPolyLine3D.h:33
A 3D polymarker.
virtual Int_t SetNextPoint(Double_t x, Double_t y, Double_t z)
Set point following LastPoint to x, y, z.
void Draw(Option_t *option="") override
Draws 3-D polymarker with its current attributes.
Double_t Rndm() override
Machine independent random number generator.
Definition TRandom.cxx:558
virtual Double_t Uniform(Double_t x1=1)
Returns a uniform deviate on the interval (0, x1).
Definition TRandom.cxx:681
Stopwatch class.
Definition TStopwatch.h:28
Double_t RealTime()
Stop the stopwatch (if it is running) and return the realtime (in seconds) passed between the start a...
void Start(Bool_t reset=kTRUE)
Start the stopwatch.
Double_t CpuTime()
Stop the stopwatch (if it is running) and return the cputime (in seconds) passed between the start an...
void Stop()
Stop the stopwatch.
void Reset()
Definition TStopwatch.h:52
void Print(Option_t *option="") const override
Print the real and cpu time passed between the start and stop events.
Basic string class.
Definition TString.h:138
void ToLower()
Change string to lower-case.
Definition TString.cxx:1189
const char * Data() const
Definition TString.h:384
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString.
Definition TString.cxx:2384
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition TString.h:641
void SetOptStat(Int_t stat=1)
The type of information printed in the histogram statistics box can be selected via the parameter mod...
Definition TStyle.cxx:1641
A TTree represents a columnar dataset.
Definition TTree.h:89
Abstract class for geometry checkers.
TPaveText * pt
TLine * line
void box(Int_t pat, Double_t x1, Double_t y1, Double_t x2, Double_t y2)
Definition fillpatterns.C:1
const Double_t sigma
Double_t y[n]
Definition legend1.C:17
return c1
Definition legend1.C:41
Double_t x[n]
Definition legend1.C:17
TH1F * h1
Definition legend1.C:5
return c2
Definition legend2.C:14
return c3
Definition legend3.C:15
Double_t ACos(Double_t)
Returns the principal value of the arc cosine of x, expressed in radians.
Definition TMath.h:643
Short_t Max(Short_t a, Short_t b)
Returns the largest of a and b.
Definition TMathBase.h:249
Double_t Log(Double_t x)
Returns the natural logarithm of x.
Definition TMath.h:767
Double_t Sqrt(Double_t x)
Returns the square root of x.
Definition TMath.h:673
Short_t Min(Short_t a, Short_t b)
Returns the smallest of a and b.
Definition TMathBase.h:197
Double_t Cos(Double_t)
Returns the cosine of an angle of x radians.
Definition TMath.h:605
constexpr Double_t Pi()
Definition TMath.h:40
Double_t Sin(Double_t)
Returns the sine of an angle of x radians.
Definition TMath.h:599
Short_t Abs(Short_t d)
Returns the absolute value of parameter Short_t d.
Definition TMathBase.h:122
constexpr Double_t TwoPi()
Definition TMath.h:47
Simple internal structure keeping a cache of mesh points per shape.
Definition TGeoChecker.h:45
Policy stamp: when this changes, cached point values may be wrong -> clear.
Definition TGeoChecker.h:51
TString fName
display name
Statefull info for the current geometry level.
TMarker m
Definition textangle.C:8