ROOTGeomAnalyzer.cxx
Go to the documentation of this file.
1 //____________________________________________________________________________
2 /*
3  Copyright (c) 2003-2020, The GENIE Collaboration
4  For the full text of the license visit http://copyright.genie-mc.org
5 
6  Anselmo Meregaglia <anselmo.meregaglia \at cern.ch>
7  ETH Zurich
8 
9  Costas Andreopoulos <constantinos.andreopoulos \at cern.ch>
10  University of Liverpool & STFC Rutherford Appleton Laboratory
11 
12  Robert Hatcher <rhatcher \at fnal.gov>
13  Fermilab
14 */
15 //____________________________________________________________________________
16 
17 #include <cassert>
18 #include <cstdlib>
19 #include <iomanip>
20 #include <set>
21 
22 #include <TGeoVolume.h>
23 #include <TGeoManager.h>
24 #include <TGeoShape.h>
25 #include <TGeoMedium.h>
26 #include <TGeoMaterial.h>
27 #include <TGeoMatrix.h>
28 #include <TGeoNode.h>
29 #include <TObjArray.h>
30 #include <TLorentzVector.h>
31 #include <TList.h>
32 #include <TSystem.h>
33 #include <TMath.h>
34 #include <TPolyMarker3D.h>
35 #include <TGeoBBox.h>
36 
37 #include "Framework/Conventions/GBuild.h"
50 
51 using namespace genie;
52 using namespace genie::geometry;
53 using namespace genie::controls;
54 
55 //#define RWH_DEBUG
56 //#define RWH_DEBUG_2
57 //#define RWH_COUNTVOLS
58 
59 #ifdef RWH_COUNTVOLS
60 // keep some statistics about how many volumes traversed for each box face
61 long int mxsegments = 0; //rwh
62 long int curface = 0; //rwh
63 long int nswims[6] = { 0, 0, 0, 0, 0, 0}; //rwh
64 long int nnever[6] = { 0, 0, 0, 0, 0, 0}; //rwh
65 double dnvols[6] = { 0, 0, 0, 0, 0, 0}; //rwh
66 double dnvols2[6] = { 0, 0, 0, 0, 0, 0}; //rwh
67 bool accum_vol_stat = false;
68 #endif
69 
70 //___________________________________________________________________________
71 ROOTGeomAnalyzer::ROOTGeomAnalyzer(string geometry_filename)
72  : GeomAnalyzerI()
73 {
74 ///
75 /// Constructor from a geometry file
76 ///
77  LOG("GROOTGeom", pDEBUG)
78  << "ROOTGeomAnalyzer ctor \"" << geometry_filename << "\"";
79  this->Initialize();
80  this->Load(geometry_filename);
81 }
82 
83 //___________________________________________________________________________
85  : GeomAnalyzerI()
86 {
87 ///
88 /// Constructor from a TGeoManager
89 ///
90  LOG("GROOTGeom", pDEBUG)
91  << "ROOTGeomAnalyzer ctor passed TGeoManager*";
92  this->Initialize();
93  this->Load(gm);
94 }
95 
96 //___________________________________________________________________________
98 {
99  this->CleanUp();
100 
101  if ( fmxddist > 0 || fmxdstep > 0 )
102  LOG("GROOTGeom",pNOTICE)
103  << "ROOTGeomAnalyzer "
104  << " mxddist " << fmxddist
105  << " mxdstep " << fmxdstep;
106 }
107 
108 //===========================================================================
109 // Geometry driver interface implementation:
110 
111 //___________________________________________________________________________
113 {
114  return *fCurrPDGCodeList;
115 }
116 
117 //___________________________________________________________________________
119 {
120 /// Computes the maximum path lengths for all materials in the input
121 /// geometry. The computed path lengths are in SI units (kgr/m^2, if
122 /// density weighting is enabled)
123 
124  LOG("GROOTGeom", pNOTICE)
125  << "Computing the maximum path lengths for all materials";
126 
127  if (!fGeometry) {
128  LOG("GROOTGeom", pFATAL) << "No ROOT geometry is loaded!!";
129  exit(1);
130  }
131 
132  //-- initialize max path lengths
134 
135  //-- select maximum path length calculation method
136  if ( fFlux ) {
137  this->MaxPathLengthsFluxMethod();
138  // clear any accumulated exposure accounted generated
139  // while exploring the geometry
140  fFlux->Clear("CycleHistory");
141  } else {
142  this->MaxPathLengthsBoxMethod();
143  }
144 
145  return *fCurrMaxPathLengthList;
146 }
147 
148 //___________________________________________________________________________
150  const TLorentzVector & x, const TLorentzVector & p)
151 {
152 /// Computes the path-length within each detector material for a
153 /// neutrino starting from point x (master coord) and travelling along
154 /// the direction of p (master coord).
155 /// The computed path lengths are in SI units (kgr/m^2, if density
156 /// weighting is enabled)
157 
158  //LOG("GROOTGeom", pDEBUG)
159  // << "Computing path-lengths for the input neutrino";
160 
161 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
162  LOG("GROOTGeom", pDEBUG)
163  << "\nInput nu: 4p (GeV) = " << utils::print::P4AsShortString(&p)
164  << ", 4x (m,s) = " << utils::print::X4AsString(&x);
165 #endif
166 
167  // if trimming configure with neutrino ray's info
168  if ( fGeomVolSelector ) {
171  }
172 
173  TVector3 udir = p.Vect().Unit(); // unit vector along direction
174  TVector3 pos = x.Vect(); // initial position
175  this->SI2Local(pos); // SI -> curr geom units
176 
177  if (!fMasterToTopIsIdentity) {
178  this->Master2Top(pos); // transform position (master -> top)
179  this->Master2TopDir(udir); // transform direction (master -> top)
180  }
181 
182  // reset current list of path-lengths
184 
185  //loop over materials & compute the path-length
187  for (itr=fCurrPDGCodeList->begin();itr!=fCurrPDGCodeList->end();itr++) {
188 
189  int pdgc = *itr;
190 
191  Double_t pl = this->ComputePathLengthPDG(pos,udir,pdgc);
193 
194 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
195  LOG("GROOTGeom", pINFO)
196  <<"Calculated path length for material: " << pdgc << " = " << pl;
197 #endif
198 
199  } // loop over materials
200 
201  this->Local2SI(*fCurrPathLengthList); // curr geom units -> SI
202 
203  return *fCurrPathLengthList;
204 }
205 
206 //___________________________________________________________________________
208  const TLorentzVector & x, const TLorentzVector & p, int tgtpdg)
209 {
210 /// Generates a random vertex, within the detector material with the input
211 /// PDG code, for a neutrino starting from point x (master coord) and
212 /// travelling along the direction of p (master coord).
213 
214  LOG("GROOTGeom", pNOTICE)
215  << "Generating vtx in material: " << tgtpdg
216  << " along the input neutrino direction";
217 
218  int nretry = 0;
219  retry: // goto label in case of abject failure
220  nretry++;
221 
222  // reset current interaction vertex
223  fCurrVertex->SetXYZ(0.,0.,0.);
224 
225 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
226  LOG("GROOTGeom", pDEBUG)
227  << "\nInput nu: 4p (GeV) = " << utils::print::P4AsShortString(&p)
228  << ", 4x (m,s) = " << utils::print::X4AsString(&x);
229 #endif
230 
231  if (!fGeometry) {
232  LOG("GROOTGeom", pFATAL) << "No ROOT geometry is loaded!!";
233  exit(1);
234  }
235 
236  // calculate the max path length for the selected material starting from
237  // x and looking along the direction of p
238  TVector3 udir = p.Vect().Unit();
239  TVector3 pos = x.Vect();
240  this->SI2Local(pos); // SI -> curr geom units
241 
242  if (!fMasterToTopIsIdentity) {
243  this->Master2Top(pos); // transform position (master -> top)
244  this->Master2TopDir(udir); // transform direction (master -> top)
245  }
246 
247  double maxwgt_dist = this->ComputePathLengthPDG(pos,udir,tgtpdg);
248  if ( maxwgt_dist <= 0 ) {
249  LOG("GROOTGeom", pERROR)
250  << "The current trajectory does not cross the selected material!!";
251  return *fCurrVertex;
252  }
253 
254  // generate random number between 0 and max_dist
255  RandomGen * rnd = RandomGen::Instance();
256  double genwgt_dist(maxwgt_dist * rnd->RndGeom().Rndm());
257 
258  LOG("GROOTGeom", pINFO)
259  << "Swim mass: Top Vol dir = " << utils::print::P3AsString(&udir)
260  << ", pos = " << utils::print::Vec3AsString(&pos);
261  LOG("GROOTGeom", pINFO)
262  << "Max {L x Density x Weight} given (init,dir) = " << maxwgt_dist;
263  LOG("GROOTGeom", pINFO)
264  << "Generated 'distance' in selected material = " << genwgt_dist;
265 #ifdef RWH_DEBUG
266  if ( ( fDebugFlags & 0x01 ) ) {
268  LOG("GROOTGeom", pINFO) << *fCurrPathSegmentList; //RWH
269  double mxddist = 0, mxdstep = 0;
270  fCurrPathSegmentList->CrossCheck(mxddist,mxdstep);
271  fmxddist = TMath::Max(fmxddist,mxddist);
272  fmxdstep = TMath::Max(fmxdstep,mxdstep);
273  }
274 #endif
275 
276  // compute the pdg weight for each material just once, then use a stl map
282  // loop over map to get tgt weight for each material (once)
283  // steps outside the geometry may have no assigned material
284  for ( ; mitr != mitr_end; ++mitr ) {
285  const TGeoMaterial* mat = mitr->first;
286  double wgt = ( mat ) ? this->GetWeight(mat,tgtpdg) : 0;
287  wgtmap[mat] = wgt;
288 #ifdef RWH_DEBUG
289  if ( ( fDebugFlags & 0x02 ) ) {
290  LOG("GROOTGeom", pINFO)
291  << " wgtmap[" << mat->GetName() << "] pdg " << tgtpdg << " wgt " << Form("%.6f",wgt);
292  }
293 #endif
294  }
295 
296  // walk down the path to pick the vertex
300  double walked = 0;
301  for ( sitr = segments.begin(); sitr != segments.end(); ++sitr) {
302  const genie::geometry::PathSegment& seg = *sitr;
303  const TGeoMaterial* mat = seg.fMaterial;
304  double trimmed_step = seg.GetSummedStepRange();
305  double wgtstep = trimmed_step * wgtmap[mat];
306  double beyond = walked + wgtstep;
307 #ifdef RWH_DEBUG
308  if ( ( fDebugFlags & 0x04 ) ) {
309  LOG("GROOTGeom", pINFO)
310  << " beyond " << beyond << " genwgt_dist " << genwgt_dist
311  << " trimmed_step " << trimmed_step << " wgtstep " << wgtstep;
312  }
313 #endif
314  if ( beyond > genwgt_dist ) {
315  // the end of this segment is beyond our generation point
316 #ifdef RWH_DEBUG
317  if ( ( fDebugFlags & 0x08 ) ) {
318  LOG("GROOTGeom", pINFO)
319  << "Choose vertex pos walked=" << walked
320  << " beyond=" << beyond
321  << " wgtstep " << wgtstep
322  << " ( " << trimmed_step << "*" << wgtmap[mat] << ")"
323  << " look for " << genwgt_dist
324  << " in " << seg.fVolume->GetName() << " "
325  << mat->GetName();
326  }
327 #endif
328  // choose a vertex in this segment (possibly multiple steps)
329  double frac = ( genwgt_dist - walked ) / wgtstep;
330  if ( frac > 1.0 ) {
331  LOG("GROOTGeom", pWARN)
332  << "Hey, frac = " << frac << " ( > 1.0 ) "
333  << genwgt_dist << " " << walked << " " << wgtstep;
334  }
335  pos = seg.GetPosition(frac);
336  fGeometry -> SetCurrentPoint (pos[0],pos[1],pos[2]);
337  fGeometry -> FindNode();
338  LOG("GROOTGeom", pINFO)
339  << "Choose vertex position in " << seg.fVolume->GetName() << " "
341  break;
342  }
343  walked = beyond;
344  }
345 
346  LOG("GROOTGeom", pNOTICE)
347  << "The vertex was placed in volume: "
348  << fGeometry->GetCurrentVolume()->GetName()
349  << ", path: " << fGeometry->GetPath();
350 
351  // warn for any volume overshoots
352  bool ok = this->FindMaterialInCurrentVol(tgtpdg);
353  if (!ok) {
354  LOG("GROOTGeom", pWARN)
355  << "Geometry volume was probably overshot";
356  LOG("GROOTGeom", pWARN)
357  << "No material with code = " << tgtpdg << " could be found at genwgt_dist="
358  << genwgt_dist << " (maxwgt_dist=" << maxwgt_dist << ")";
359  if ( nretry < 10 ) {
360  LOG("GROOTGeom", pWARN)
361  << "retry placing vertex";
362  goto retry; // yeah, I know! MyBad.
363  }
364  }
365 
366  if (!fMasterToTopIsIdentity) {
367  this->Top2Master(pos); // transform position (top -> master)
368  }
369 
370  this->Local2SI(pos); // curr geom units -> SI
371 
372  fCurrVertex->SetXYZ(pos[0],pos[1],pos[2]);
373 
374 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
375  LOG("GROOTGeom", pDEBUG)
376  << "Vtx (m) = " << utils::print::Vec3AsString(&pos);
377 #endif
378 
379  return *fCurrVertex;
380 }
381 
382 //===========================================================================
383 // Driver configuration methods:
384 
385 //___________________________________________________________________________
387 {
388 /// Use the units of the input geometry,
389 /// e.g. SetLengthUnits(genie::units::centimeter)
390 /// GENIE uses the physical system of units (hbar=c=1) almost throughtout
391 /// so everything is expressed in GeV but when analyzing detector geometries
392 /// use meters. Setting input geometry units will allow the code to compute
393 /// the conversion factor.
394 /// As input, use one of the constants in $GENIE/src/Conventions/Units.h
395 
397  LOG("GROOTGeom", pNOTICE)
398  << "Geometry length units scale factor (geom units -> m): "
399  << fLengthScale;
400 }
401 
402 //___________________________________________________________________________
404 {
405 /// Like SetLengthUnits, but for density (default units = kgr/m3)
406 
408  LOG("GROOTGeom", pNOTICE)
409  << "Geometry density units scale factor (geom units -> kgr/m3): "
410  << fDensityScale;
411 }
412 
413 //___________________________________________________________________________
415 {
416 /// Set a factor that can multiply the computed max path lengths.
417 /// The maximum path lengths are computed by performing an MC scanning of
418 /// the input geometry. If you configure the scanner with a low number of
419 /// points or rays you might understimate the path lengths, so you might
420 /// want to 'inflate' them a little bit using this method.
421 /// Do not set this number too high, because the max interaction probability
422 /// will be grossly overestimated and you would need lots of attempts before
423 /// getting a flux neutrino to interact...
424 
425  fMaxPlSafetyFactor = sf;
426 
427  LOG("GROOTGeom", pNOTICE)
428  << "Max path length safety factor: " << fMaxPlSafetyFactor;
429 }
430 
431 //___________________________________________________________________________
433 {
434 /// Set it to x, if the relative weight proportions of elements in a mixture
435 /// add up to x (eg x=1, 100, etc). Set it to a negative value to explicitly
436 /// compute the correct weight normalization.
437 
438  fMixtWghtSum = sum;
439 }
440 
441 //___________________________________________________________________________
443 {
444 /// Set the name of the top volume.
445 /// This driver would ask the TGeoManager::GetTopVolume() for the top volume.
446 /// Use this method for changing this if for example you want to set a smaller
447 /// volume as the top one so as to generate events only in a specific part of
448 /// your detector.
449 
450  if (name.size() == 0) return;
451 
453  LOG("GROOTGeom",pNOTICE) << "Geometry Top Volume name: " << fTopVolumeName;
454 
455  TGeoVolume * gvol = fGeometry->GetVolume(fTopVolumeName.c_str());
456  if (!gvol) {
457  LOG("GROOTGeom",pWARN) << "Could not find volume: " << name.c_str();
458  LOG("GROOTGeom",pWARN) << "Will not change the current top volume";
459  fTopVolumeName = "";
460  return;
461  }
462 
463  // Get a matrix connecting coordinates of master and top volumes.
464  // The matrix will be used for transforming the coordinates of incoming
465  // flux neutrinos & generated interaction vertices.
466  // This is needed (in case that the input top volume != master volume)
467  // because ROOT always sets the coordinate system origin at the centre of
468  // the specified top volume (whereas GENIE assumes that the global reference
469  // frame is that of the master volume)
470 
471  TGeoIterator next(fGeometry->GetMasterVolume());
472  TGeoNode *node;
473  TString nodeName, volNameStr;
474  const char* volName = fTopVolumeName.c_str();
475  while ((node = next())) {
476  nodeName = node->GetVolume()->GetName();
477  if (nodeName == volName) {
478  if (fMasterToTop) delete fMasterToTop;
479  fMasterToTop = new TGeoHMatrix(*next.GetCurrentMatrix());
480  fMasterToTopIsIdentity = fMasterToTop->IsIdentity();
481  break;
482  }
483  }
484 
485  // set volume name
486  fTopVolume = gvol;
487  fGeometry->SetTopVolume(fTopVolume);
488 }
489 
490 //===========================================================================
491 // Geometry/Unit transforms:
492 
493 //___________________________________________________________________________
495 {
496 /// convert path lengths from current geometry units to SI units
497 ///
498 
499  double scaling_factor = this->LengthUnits();
500  if (this->WeightWithDensity()) { scaling_factor *= this->DensityUnits(); }
501 
502 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
503  LOG("GROOTGeom", pDEBUG)
504  << "Scaling path-lengths from local units -> meters "
505  << ((this->WeightWithDensity()) ? "* kgr/m^3" : "")
506  << " - scale = " << scaling_factor;
507 #endif
508 
510  for(pliter = pl.begin(); pliter != pl.end(); ++pliter)
511  {
512  int pdgc = pliter->first;
513  pl.ScalePathLength(pdgc, scaling_factor);
514  }
515 }
516 
517 //___________________________________________________________________________
518 void ROOTGeomAnalyzer::Local2SI(TVector3 & vec) const
519 {
520 /// convert position vector from current geometry units to SI units
521 ///
522 
523 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
524  LOG("GROOTGeom", pDEBUG)
525  << "Position (loc): " << utils::print::Vec3AsString(&vec);
526 #endif
527 
528  vec *= (this->LengthUnits());
529 
530 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
531  LOG("GROOTGeom", pDEBUG)
532  << "Position (SI): " << utils::print::Vec3AsString(&vec);
533 #endif
534 }
535 
536 //___________________________________________________________________________
537 void ROOTGeomAnalyzer::SI2Local(TVector3 & vec) const
538 {
539 /// convert position vector from SI units to current geometry units
540 ///
541 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
542  LOG("GROOTGeom", pDEBUG)
543  << "Position (SI): " << utils::print::Vec3AsString(&vec);
544 #endif
545 
546  vec *= (1./this->LengthUnits());
547 
548 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
549  LOG("GROOTGeom", pDEBUG)
550  << "Position (loc): " << utils::print::Vec3AsString(&vec);
551 #endif
552 }
553 
554 //___________________________________________________________________________
555 void ROOTGeomAnalyzer::Master2Top(TVector3 & vec) const
556 {
557 /// transform the input position vector from the master volume coordinate
558 /// system to the specified top volume coordinate system, but not
559 /// change the units.
560 
561 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
562  LOG("GROOTGeom", pDEBUG)
563  << "Position (coord:master): " << utils::print::Vec3AsString(&vec);
564 #endif
565 
566  Double_t mast[3], top[3];
567  vec.GetXYZ(mast);
568  fMasterToTop->MasterToLocal(mast, top);
569  vec.SetXYZ(top[0], top[1], top[2]);
570 
571 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
572  LOG("GROOTGeom", pDEBUG)
573  << "Position (coord:top): " << utils::print::Vec3AsString(&vec);
574 #endif
575 }
576 
577 //___________________________________________________________________________
578 void ROOTGeomAnalyzer::Master2TopDir(TVector3 & vec) const
579 {
580 /// transform the input direction vector from the master volume coordinate
581 /// system to the specified top volume coordinate system, but not
582 /// change the units.
583 
584 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
585  LOG("GROOTGeom", pDEBUG)
586  << "Direction (coord:master): " << utils::print::Vec3AsString(&vec);
587 #endif
588 
589  Double_t mast[3], top[3];
590  vec.GetXYZ(mast);
591  fMasterToTop->MasterToLocalVect(mast, top);
592  vec.SetXYZ(top[0], top[1], top[2]);
593 
594 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
595  LOG("GROOTGeom", pDEBUG)
596  << "Direction (coord:top): " << utils::print::Vec3AsString(&vec);
597 #endif
598 }
599 
600 //___________________________________________________________________________
601 void ROOTGeomAnalyzer::Top2Master(TVector3 & vec) const
602 {
603 /// transform the input position vector from the specified top volume
604 /// coordinate system to the master volume coordinate system, but not
605 /// change the units.
606 
607 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
608  LOG("GROOTGeom", pDEBUG)
609  << "Position (coord:top): " << utils::print::Vec3AsString(&vec);
610 #endif
611 
612  Double_t mast[3], top[3];
613  vec.GetXYZ(top);
614  fMasterToTop->LocalToMaster(top, mast);
615  vec.SetXYZ(mast[0], mast[1], mast[2]);
616 
617 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
618  LOG("GROOTGeom", pDEBUG)
619  << "Position (coord:master): " << utils::print::Vec3AsString(&vec);
620 #endif
621 }
622 
623 //___________________________________________________________________________
624 void ROOTGeomAnalyzer::Top2MasterDir(TVector3 & vec) const
625 {
626 /// transform the input direction vector from the specified top volume
627 /// coordinate system to the master volume coordinate system.
628 
629 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
630  LOG("GROOTGeom", pDEBUG)
631  << "Direction (coord:top): " << utils::print::Vec3AsString(&vec);
632 #endif
633 
634  Double_t mast[3], top[3];
635  vec.GetXYZ(top);
636  fMasterToTop->LocalToMasterVect(top, mast);
637  vec.SetXYZ(mast[0], mast[1], mast[2]);
638 
639 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
640  LOG("GROOTGeom", pDEBUG)
641  << "Direction (coord:master): " << utils::print::Vec3AsString(&vec);
642 #endif
643 }
644 
645 //===========================================================================
646 // Private methods:
647 
648 //___________________________________________________________________________
650 {
651  LOG("GROOTGeom", pNOTICE)
652  << "Initializing ROOT geometry driver & setting defaults";
653 
657  fGeomVolSelector = 0;
658  fCurrPDGCodeList = 0;
659  fTopVolume = 0;
660  fTopVolumeName = "";
661  fKeepSegPath = false;
662 
663  // some defaults:
664  this -> SetScannerNPoints (200);
665  this -> SetScannerNRays (200);
666  this -> SetScannerNParticles (10000);
667  this -> SetScannerFlux (0);
668  this -> SetMaxPlSafetyFactor (1.1);
671  this -> SetWeightWithDensity (true);
672  this -> SetMixtureWeightsSum (-1.);
673 
674  fMasterToTopIsIdentity = true;
675 
676  fmxddist = 0;
677  fmxdstep = 0;
678  fDebugFlags = 0;
679 }
680 
681 //___________________________________________________________________________
683 {
684  LOG("GROOTGeom", pNOTICE) << "Cleaning up...";
685 
689  if ( fCurrPDGCodeList ) delete fCurrPDGCodeList;
690  if ( fMasterToTop ) delete fMasterToTop;
691 }
692 
693 //___________________________________________________________________________
695 {
696 /// Load the detector geometry from the input ROOT file
697 ///
698  LOG("GROOTGeom", pNOTICE) << "Loading geometry from: " << filename;
699 
700  bool is_accessible = ! (gSystem->AccessPathName( filename.c_str() ));
701  if (!is_accessible) {
702  LOG("GROOTGeom", pFATAL)
703  << "The ROOT geometry doesn't exist! Initialization failed!";
704  exit(1);
705  }
706 
707 // ROOT versions 6.16 - 6.24 defaulted to kG4Units [ugh]
708 #if ROOT_VERSION_CODE >= ROOT_VERSION(6,16,0)
709  if (TGeoManager::GetDefaultUnits() != TGeoManager::kRootUnits) {
710  TGeoManager::LockDefaultUnits(false);
711  TGeoManager::SetDefaultUnits(TGeoManager::kRootUnits);
712  TGeoManager::LockDefaultUnits(true);
713  }
714 #endif
715 
716  TGeoManager * gm = TGeoManager::Import(filename.c_str());
717 
718  this->Load(gm);
719 }
720 
721 //___________________________________________________________________________
722 void ROOTGeomAnalyzer::Load(TGeoManager * gm)
723 {
724 /// Load the detector geometry from the input TGeoManager
725 
726  LOG("GROOTGeom", pNOTICE)
727  << "A TGeoManager is being loaded to the geometry driver";
728  fGeometry = gm;
729 
730  if (!fGeometry) {
731  LOG("GROOTGeom", pFATAL) << "Null TGeoManager! Aborting";
732  }
733  assert(fGeometry);
734 
735  this->BuildListOfTargetNuclei();
736 
737  const PDGCodeList & pdglist = this->ListOfTargetNuclei();
738 
739  fTopVolume = 0;
741  fCurrPathLengthList = new PathLengthList(pdglist);
742  fCurrMaxPathLengthList = new PathLengthList(pdglist);
743  fCurrVertex = new TVector3(0.,0.,0.);
744 
745  // ask geometry manager for its top volume
746  fTopVolume = fGeometry->GetTopVolume();
747  if (!fTopVolume) {
748  LOG("GROOTGeom", pFATAL) << "Could not get top volume!!!";
749  }
750  assert(fTopVolume);
751 
752  // load matrix (identity) of top volume
753  fMasterToTop = new TGeoHMatrix(*fGeometry->GetCurrentMatrix());
754  fMasterToTopIsIdentity = true;
755 
756 //#define PRINT_MATERIALS
757 #ifdef PRINT_MATERIALS
758  fGeometry->GetListOfMaterials()->Print();
759  fGeometry->GetListOfMedia()->Print();
760 #endif
761 
762 }
763 
764 //___________________________________________________________________________
766 {
767 /// Determine possible target PDG codes.
768 /// Note: If one is using a top volume other than the master level
769 /// then the final list might include PDG codes that will never
770 /// be seen during swimming through the volumes if those code are only
771 /// found in materials outside the top volume.
772 
774 
775  if (!fGeometry) {
776  LOG("GROOTGeom", pFATAL) << "No ROOT geometry is loaded!!";
777  exit(1);
778  }
779 
780  TObjArray * volume_list = fGeometry->GetListOfVolumes();
781  if (!volume_list) {
782  LOG("GROOTGeom", pERROR)
783  << "Null list of geometry volumes. Can not find build target list!";
784  return;
785  }
786 
787  std::set<Int_t> seen_mat; // list of materials we've already handled
788  std::vector<TGeoVolume*> volvec; //RWH
789 
790  int numVol = volume_list->GetEntries();
791 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
792  LOG("GROOTGeom", pDEBUG) << "Number of volumes found: " << numVol;
793 #endif
794 
795  for (int ivol = 0; ivol < numVol; ivol++) {
796  TGeoVolume * volume = dynamic_cast <TGeoVolume *>(volume_list->At(ivol));
797  if (!volume) {
798  LOG("GROOTGeom", pWARN)
799  << "Got a null geometry volume!! Skiping current list element";
800  continue;
801  }
802  TGeoMaterial * mat = volume->GetMedium()->GetMaterial();
803 
804  // shortcut if we've already seen this material
805  Int_t mat_indx = mat->GetIndex();
806  if ( seen_mat.find(mat_indx) != seen_mat.end() ) continue;
807  seen_mat.insert(mat_indx);
808  volvec.push_back(volume); //RWH
809 
810  if (mat->IsMixture()) {
811  TGeoMixture * mixt = dynamic_cast <TGeoMixture*> (mat);
812  int Nelements = mixt->GetNelements();
813  for (int i=0; i<Nelements; i++) {
814  int ion_pdgc = this->GetTargetPdgCode(mixt,i);
815  fCurrPDGCodeList->push_back(ion_pdgc);
816  }
817  } else {
818  int ion_pdgc = this->GetTargetPdgCode(mat);
819  fCurrPDGCodeList->push_back(ion_pdgc);
820  }
821  }
822  // sort the list
823  // we don't calculate this list but once per geometry and a sorted
824  // list is easier to read so this doesn't cost much
825  std::sort(fCurrPDGCodeList->begin(),fCurrPDGCodeList->end());
826 
827 }
828 
829 //___________________________________________________________________________
830 int ROOTGeomAnalyzer::GetTargetPdgCode(const TGeoMaterial * const m) const
831 {
832  int A = TMath::Nint(m->GetA());
833  int Z = TMath::Nint(m->GetZ());
834 
835  int pdgc = pdg::IonPdgCode(A,Z);
836 
837  return pdgc;
838 }
839 
840 //___________________________________________________________________________
842  const TGeoMixture * const m, int ielement) const
843 {
844  int A = TMath::Nint(m->GetAmixt()[ielement]);
845  int Z = TMath::Nint(m->GetZmixt()[ielement]);
846 
847  int pdgc = pdg::IonPdgCode(A,Z);
848 
849  return pdgc;
850 }
851 
852 //___________________________________________________________________________
853 double ROOTGeomAnalyzer::GetWeight(const TGeoMaterial * mat, int pdgc)
854 {
855 /// Get the weight of the input material.
856 /// Return the weight only if the material's pdg code matches the input code.
857 /// If the material is found to be a mixture, call the corresponding method
858 /// for mixtures.
859 /// Weight is in the curr geom density units.
860 
861  if (!mat) {
862  LOG("GROOTGeom", pERROR) << "Null input material. Return weight = 0.";
863  return 0;
864  }
865 
867  if (!exists) {
868  LOG("GROOTGeom", pERROR) << "Target doesn't exist. Return weight = 0.";
869  return 0;
870  }
871 
872 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
873  LOG("GROOTGeom",pDEBUG)
874  << "Curr. material: A/Z = " << mat->GetA() << " / " << mat->GetZ();
875 #endif
876 
877  // if the input material is a mixture, get a the sum of weights for
878  // all matching elements
879  double weight = 0.;
880  if (mat->IsMixture()) {
881  const TGeoMixture * mixt = dynamic_cast <const TGeoMixture*> (mat);
882  if (!mixt) {
883  LOG("GROOTGeom", pERROR) << "Null input mixture. Return weight = 0.";
884  return 0;
885  }
886 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
887  LOG("GROOTGeom", pDEBUG)
888  << "Material : " << mat->GetName()
889  << " is a mixture with " << mixt->GetNelements() << " elements";
890 #endif
891  // loop over elements & sum weights of matching elements
892  weight = this->GetWeight(mixt,pdgc);
893  return weight;
894  } // is mixture?
895 
896  // pure material
897  int ion_pdgc = this->GetTargetPdgCode(mat);
898  if (ion_pdgc != pdgc) return 0.;
899 
900  if (this->WeightWithDensity())
901  weight = mat->GetDensity(); // material density (curr geom units)
902  else
903  weight = 1.0;
904 
905 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
906  LOG("GROOTGeom", pDEBUG)
907  << "Weight[mat:" << mat->GetName() << "] = " << weight;
908 #endif
909 
910  return weight;
911 }
912 
913 //___________________________________________________________________________
914 double ROOTGeomAnalyzer::GetWeight(const TGeoMixture * mixt, int pdgc)
915 {
916 /// Loop over the mixture elements, find the one matching the input pdgc
917 /// and return its weight.
918 /// Weight is in the curr geom density units.
919 
920  double weight = 0;
921 
922  int nm = 0;
923  for (int i = 0; i < mixt->GetNelements(); i++) {
924  double dw = (this->GetWeight(mixt,i,pdgc));
925  if (dw>0) nm++;
926  weight += dw;
927  }
928 
929  if (nm>1) {
930  for (int j = 0; j < mixt->GetNelements(); j++) {
931  LOG("GROOTGeom", pWARN)
932  << "[" << j << "] Z = " << mixt->GetZmixt()[j]
933  << ", A = " << mixt->GetAmixt()[j]
934  << " (pdgc = " << this->GetTargetPdgCode(mixt,j)
935  << "), w = " << mixt->GetWmixt()[j];
936  }
937  LOG("GROOTGeom", pERROR)
938  << "Material pdgc = " << pdgc << " appears " << nm
939  << " times (>1) in mixture = " << mixt->GetName();
940  LOG("GROOTGeom", pFATAL)
941  << "Your geometry must be incorrect - Aborting";
942  exit(1);
943  }
944 
945  // if we are not weighting with the density then the weight=1 if the pdg
946  // code was matched for any element of this mixture
947  if ( !this->WeightWithDensity() && weight>0. ) weight=1.0;
948 
949  return weight;
950 }
951 
952 //___________________________________________________________________________
953 double ROOTGeomAnalyzer::GetWeight(const TGeoMixture* mixt, int ielement, int pdgc)
954 {
955 /// Get the weight of the input ith element of the input material.
956 /// Return the weight only if the element's pdg code matches the input code.
957 /// Weight is in the curr geom density units.
958 
959 // int ion_pdgc = this->GetTargetPdgCode(mixt->GetElement(ielement));
960  int ion_pdgc = this->GetTargetPdgCode(mixt, ielement);
961  if (ion_pdgc != pdgc) return 0.;
962 
963  double d = mixt->GetDensity(); // mixture density (curr geom units)
964  double w = mixt->GetWmixt()[ielement]; // relative proportion by mass
965 
966  double wtot = this->MixtureWeightsSum();
967 
968  // <0 forces explicit calculation of relative proportion normalization
969  if (wtot < 0) {
970  wtot = 0;
971  for (int i = 0; i < mixt->GetNelements(); i++) {
972  wtot += (mixt->GetWmixt()[i]);
973  }
974  }
975  assert(wtot>0);
976 
977  w /= wtot;
978  double weight = d*w;
979 
980  return weight;
981 }
982 
983 //___________________________________________________________________________
985 {
986 /// Use the input flux driver to generate "rays", and then follow them through
987 /// the detector and figure out the maximum path length for each material
988 
989  LOG("GROOTGeom", pNOTICE)
990  << "Computing the maximum path lengths using the FLUX method";
991 
992  int iparticle = 0;
994 
995  const int nparticles = abs(this->ScannerNParticles());
996 
997  // if # scanner particles is negative, this signals that the user
998  // desires to force rays to have the maximum energy (useful if the
999  // volume considered changes size with neutrino energy)
1000  bool rescale_e = (this->ScannerNParticles() < 0 );
1001  double emax = fFlux->MaxEnergy();
1002  if ( rescale_e ) {
1003  LOG("GROOTGeom", pNOTICE)
1004  << "max path lengths with FLUX method forcing Enu=" << emax;
1005  }
1006 
1007  while (iparticle < nparticles ) {
1008 
1009  bool ok = fFlux->GenerateNext();
1010  if (!ok) {
1011  LOG("GROOTGeom", pWARN) << "Couldn't generate a flux neutrino";
1012  continue;
1013  }
1014 
1015  TLorentzVector nup4 = fFlux->Momentum();
1016  if ( rescale_e ) {
1017  double ecurr = nup4.E();
1018  if ( ecurr > 0 ) nup4 *= (emax/ecurr);
1019  }
1020  const TLorentzVector & nux4 = fFlux->Position();
1021 
1022  //LOG("GMCJDriver", pNOTICE)
1023  // << "\n [-] Generated flux neutrino: "
1024  // << "\n |----o 4-momentum : " << utils::print::P4AsString(&nup4)
1025  // << "\n |----o 4-position : " << utils::print::X4AsString(&nux4);
1026 
1027  const PathLengthList & pl = this->ComputePathLengths(nux4, nup4);
1028 
1029  bool enters = false;
1030 
1031  for (pl_iter = pl.begin(); pl_iter != pl.end(); ++pl_iter) {
1032  int pdgc = pl_iter->first;
1033  double pathlength = pl_iter->second;
1034 
1035  if ( pathlength > 0 ) {
1036  pathlength *= (this->MaxPlSafetyFactor());
1037 
1038  pathlength = TMath::Max(pathlength, fCurrMaxPathLengthList->PathLength(pdgc));
1039  fCurrMaxPathLengthList->SetPathLength(pdgc,pathlength);
1040  enters = true;
1041  }
1042  }
1043  if (enters) iparticle++;
1044  }
1045 }
1046 
1047 //___________________________________________________________________________
1049 {
1050 /// Generate points in the geometry's bounding box and for each point
1051 /// generate random rays, follow them through the detector and figure out
1052 /// the maximum path length for each material
1053 
1054  LOG("GROOTGeom", pNOTICE)
1055  << "Computing the maximum path lengths using the BOX method";
1056 #ifdef RWH_COUNTVOLS
1057  accum_vol_stat = true;
1058 #endif
1059 
1060  int iparticle = 0;
1061  bool ok = true;
1062  TLorentzVector nux4;
1063  TLorentzVector nup4;
1064 
1066 
1067  while ( (ok = this->GenBoxRay(iparticle++,nux4,nup4)) ) {
1068 
1069  //LOG("GMCJDriver", pNOTICE)
1070  // << "\n [-] Generated flux neutrino: "
1071  // << "\n |----o 4-momentum : " << utils::print::P4AsString(&nup4)
1072  // << "\n |----o 4-position : " << utils::print::X4AsString(&nux4);
1073 
1074  const PathLengthList & pllst = this->ComputePathLengths(nux4, nup4);
1075 
1076  for (pl_iter = pllst.begin(); pl_iter != pllst.end(); ++pl_iter) {
1077  int pdgc = pl_iter->first;
1078  double pl = pl_iter->second;
1079 
1080  if (pl>0) {
1081  pl *= (this->MaxPlSafetyFactor());
1082 
1083  pl = TMath::Max(pl, fCurrMaxPathLengthList->PathLength(pdgc));
1085  }
1086  }
1087  }
1088 
1089  // print out the results
1090  LOG("GROOTGeom", pDEBUG)
1091  << "DensWeight \"" << (fDensWeight?"true":"false")
1092  << "\" MixtWghtSum " << fMixtWghtSum;
1093  LOG("GROOTGeom", pDEBUG) << "CurrMaxPathLengthList: "
1095 
1096 #ifdef RWH_COUNTVOLS
1097  // rwh
1098  // print statistics for average,rms of number of volumes seen for
1099  // various rays for each face
1100  for (int j = 0; j < 6; ++j ) {
1101  long int ns = nswims[j];
1102  double x = dnvols[j];
1103  double x2 = dnvols2[j];
1104  if ( ns == 0 ) ns = 1;
1105  double avg = x / (double)ns;
1106  double rms = TMath::Sqrt((x2/(double)ns) - avg*avg);
1107  LOG("GROOTGeom", pNOTICE)
1108  << "RWH: nswim after BOX face " << j << " is " << ns
1109  << " avg " << avg << " rms " << rms
1110  << " never " << nnever[j];
1111  }
1112  LOG("GROOTGeom", pNOTICE)
1113  << "RWH: Max PathSegmentList size " << mxsegments;
1114  accum_vol_stat = false;
1115 #endif
1116 
1117 }
1118 
1119 //___________________________________________________________________________
1120 bool ROOTGeomAnalyzer::GenBoxRay(int indx, TLorentzVector& x4, TLorentzVector& p4)
1121 {
1122 /// Generate points in the geometry's bounding box and for each point generate
1123 /// random rays -- a pseudo-flux -- in master coordinates and SI units
1124 
1125  firay++;
1126  fnewpnt = false;
1127 
1128  // first time through ... special case
1129  if ( indx == 0 ) { fiface = 0; fipoint = 0; firay = 0; fnewpnt = true; }
1130 
1131  if ( firay >= fNRays ) { fipoint++; firay = 0; fnewpnt = true; }
1132  if ( fipoint >= fNPoints ) { fiface++; fipoint = 0; firay = 0; fnewpnt = true; }
1133  if ( fiface >= 3 ) {
1134  LOG("GROOTGeom",pINFO) << "Box surface scanned: " << indx << " points/rays";
1135  return false; // signal end
1136  }
1137 
1138  if ( indx == 0 ) {
1139  // get geometry's bounding box
1140  //LOG("GROOTGeom", pNOTICE) << "Getting a TGeoBBox enclosing the detector";
1141  TGeoShape * TS = fTopVolume->GetShape();
1142  TGeoBBox * box = (TGeoBBox *)TS;
1143  //get box origin and dimensions (in the same units as the geometry)
1144  fdx = box->GetDX(); // half-length
1145  fdy = box->GetDY(); // half-length
1146  fdz = box->GetDZ(); // half-length
1147  fox = (box->GetOrigin())[0];
1148  foy = (box->GetOrigin())[1];
1149  foz = (box->GetOrigin())[2];
1150 
1151  LOG("GROOTGeom",pNOTICE)
1152  << "Box size (GU) :"
1153  << " x = " << 2*fdx << ", y = " << 2*fdy << ", z = " << 2*fdz;
1154  LOG("GROOTGeom",pNOTICE)
1155  << "Box origin (GU) :"
1156  << " x = " << fox << ", y = " << foy << ", z = " << foz;
1157  LOG("GROOTGeom",pNOTICE)
1158  << "Will generate [" << fNPoints << "] random points / box surface";
1159  LOG("GROOTGeom",pNOTICE)
1160  << "Will generate [" << fNRays << "] rays / point";
1161 
1162 #ifdef VALIDATE_CORNERS
1163  // RWH: test that we know the coordinate transforms for the box corners
1164  for (int sz = -1; sz <= +1; ++sz) {
1165  for (int sy = -1; sy <= +1; ++sy) {
1166  for (int sx = -1; sx <= +1; ++sx) {
1167  if (sx == 0 || sy == 0 || sz == 0 ) continue;
1168  TVector3& pos = fGenBoxRayPos;
1169  pos.SetXYZ(fox+(sx*fdx),foy+(sy*fdy),foz+(sz*fdz));
1170  TVector3 master(fGenBoxRayPos);
1171  this->Top2Master(master); // transform position (top -> master)
1172  this->Local2SI(master);
1173  TVector3 pos2(master);
1174  this->Master2Top(pos2);
1175  this->SI2Local(pos2);
1176  LOG("GROOTGeom", pNOTICE)
1177  << "TopVol corner "
1178  << " [" << pos[0] << "," << pos[1] << "," << pos[2] << "] "
1179  << "Master corner "
1180  << " [" << master[0] << "," << master[1] << "," << master[2] << "] "
1181  << " top again"
1182  << " [" << pos2[0] << "," << pos2[1] << "," << pos2[2] << "] ";
1183  }
1184  }
1185  }
1186 #endif
1187 
1188  }
1189 
1190  RandomGen * rnd = RandomGen::Instance();
1191 
1192  double eps = 0.0; //1.0e-12; // tweak to make sure we're inside the box
1193 
1194  switch ( fiface ) {
1195  case 0:
1196  {
1197  //top:
1198  if ( firay == fNRays-1 && fipoint == fNPoints-1 )
1199  LOG("GROOTGeom",pINFO) << "Box surface scanned: [TOP]";
1200  fGenBoxRayDir.SetXYZ(-0.5+rnd->RndGeom().Rndm(),
1201  -rnd->RndGeom().Rndm(),
1202  -0.5+rnd->RndGeom().Rndm());
1203  if ( fnewpnt )
1204  fGenBoxRayPos.SetXYZ(fox-fdx+eps+2*(fdx-eps)*rnd->RndGeom().Rndm(),
1205  foy+fdy-eps,
1206  foz-fdz+eps+2*(fdz-eps)*rnd->RndGeom().Rndm());
1207  break;
1208  }
1209  case 1:
1210  {
1211  //left:
1212  if ( firay == fNRays-1 && fipoint == fNPoints-1 )
1213  LOG("GROOTGeom",pINFO) << "Box surface scanned: [LEFT]";
1214  fGenBoxRayDir.SetXYZ(rnd->RndGeom().Rndm(),
1215  -0.5+rnd->RndGeom().Rndm(),
1216  -0.5+rnd->RndGeom().Rndm());
1217  if ( fnewpnt )
1218  fGenBoxRayPos.SetXYZ(fox-fdx+eps,
1219  foy-fdy+eps+2*(fdy-eps)*rnd->RndGeom().Rndm(),
1220  foz-fdz+eps+2*(fdz-eps)*rnd->RndGeom().Rndm());
1221  break;
1222  }
1223  case 2:
1224  {
1225  //front: (really what I, RWH, would call the back)
1226  if ( firay == fNRays-1 && fipoint == fNPoints-1 )
1227  LOG("GROOTGeom",pINFO) << "Box surface scanned: [FRONT]";
1228  fGenBoxRayDir.SetXYZ(-0.5+rnd->RndGeom().Rndm(),
1229  -0.5+rnd->RndGeom().Rndm(),
1230  -rnd->RndGeom().Rndm());
1231  if ( fnewpnt )
1232  fGenBoxRayPos.SetXYZ(fox-fdx+eps+2*(fdx-eps)*rnd->RndGeom().Rndm(),
1233  foy-fdy+eps+2*(fdy-eps)*rnd->RndGeom().Rndm(),
1234  foz+fdz+eps);
1235  break;
1236  }
1237  }
1238 /*
1239  //bottom:
1240  pos.SetXYZ(ox-dx+2*dx*rnd->RndGeom().Rndm(),
1241  oy-dy,
1242  oz-dz+2*dz*rnd->RndGeom().Rndm());
1243  dir.SetXYZ(-0.5+rnd->RndGeom().Rndm(),
1244  rnd->RndGeom().Rndm(),
1245  -0.5+rnd->RndGeom().Rndm());
1246  //right:
1247  pos.SetXYZ(ox+dx,
1248  oy-dy+2*dy*rnd->RndGeom().Rndm(),
1249  oz-dz+2*dz*rnd->RndGeom().Rndm());
1250  dir.SetXYZ(-rnd->RndGeom().Rndm(),
1251  -0.5+rnd->RndGeom().Rndm(),
1252  -0.5+rnd->RndGeom().Rndm());
1253  //back:
1254  pos.SetXYZ(ox-dx+2*dx*rnd->RndGeom().Rndm(),
1255  oy-dy+2*dy*rnd->RndGeom().Rndm(),
1256  oz-dz);
1257  dir.SetXYZ(-0.5+rnd->RndGeom().Rndm(),
1258  -0.5+rnd->RndGeom().Rndm(),
1259  rnd->RndGeom().Rndm());
1260 */
1261 
1262 #ifdef RWH_COUNTVOLS
1263  curface = fiface;
1264 #endif
1265 
1266 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
1267  if ( fnewpnt )
1268  LOG("GROOTGeom", pNOTICE)
1269  << "GenBoxRay(topvol) "
1270  << " iface " << fiface << " ipoint " << fipoint << " iray " << firay
1271  << " newpnt " << (fnewpnt?"true":"false")
1274 #endif
1275 
1276  if ( fnewpnt ) {
1277  if ( ! fMasterToTopIsIdentity) {
1278  this->Top2Master(fGenBoxRayPos); // transform position (top -> master)
1279  }
1280  this->Local2SI(fGenBoxRayPos);
1281  }
1282  this->Top2MasterDir(fGenBoxRayDir); // transform direction (top -> master)
1283 
1284  x4.SetVect(fGenBoxRayPos);
1285  p4.SetVect(fGenBoxRayDir.Unit());
1286 
1287 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
1288  LOG("GROOTGeom", pNOTICE)
1289  << "GenBoxRay(master) "
1290  << " iface " << fiface << " ipoint " << fipoint << " iray " << firay
1291  << " newpnt " << (fnewpnt?"true":"false")
1294 #endif
1295 
1296  return true;
1297 }
1298 
1299 //________________________________________________________________________
1301  const TVector3 & r0, const TVector3 & udir, int pdgc)
1302 {
1303 /// Compute the path length for the material with pdg-code = pdc, staring
1304 /// from the input position r (top vol coord & units) and moving along the
1305 /// direction of the unit vector udir (top vol coord).
1306 
1307  double pl = 0; // path-length (x density, if density-weighting is ON)
1308 
1309  this->SwimOnce(r0,udir);
1310 
1311  double step = 0;
1312  double weight = 0;
1313 
1314  // const TGeoVolume * vol = 0;
1315  // const TGeoMedium * med = 0;
1316  const TGeoMaterial * mat = 0;
1317 
1318  // loop over independent materials, which is shorter or equal to # of volumes
1323  for ( ; itr != itr_end; ++itr ) {
1324  mat = itr->first;
1325  if ( ! mat ) continue; // segment outside geometry has no material
1326  step = itr->second;
1327  weight = this->GetWeight(mat,pdgc);
1328  pl += (step*weight);
1329  }
1330 
1331 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
1332  LOG("GROOTGeom", pDEBUG)
1333  << "PathLength[" << pdgc << "] = " << pl << " in curr geom units";
1334 #endif
1335 
1336  return pl;
1337 }
1338 
1339 //________________________________________________________________________
1340 void ROOTGeomAnalyzer::SwimOnce(const TVector3 & r0, const TVector3 & udir)
1341 {
1342 /// Swim through the geometry from the from the input position
1343 /// r0 (top vol coord & units) and moving along the direction of the
1344 /// unit vector udir (topvol coord) to create a filled PathSegmentList
1345 
1346  int nvolswim = 0; //rwh
1347 
1349 
1350  // don't swim if the current PathSegmentList is up-to-date
1351  if ( fCurrPathSegmentList->IsSameStart(r0,udir) ) return;
1352 
1353  // start fresh
1355 
1356  // set start info so next time we don't swim for the same ray
1358 
1359  PathSegment ps_curr;
1360 
1361  bool found_vol (false);
1362  bool keep_on (true);
1363 
1364  double step = 0;
1365  double raydist = 0;
1366 
1367  const TGeoVolume * vol = 0;
1368  const TGeoMedium * med = 0;
1369  const TGeoMaterial * mat = 0;
1370 
1371  // determining the geometry path is expensive, do it only if necessary
1372  bool selneedspath = ( fGeomVolSelector && fGeomVolSelector->GetNeedPath() );
1373  const bool fill_path = fKeepSegPath || selneedspath;
1374 
1375 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
1376  LOG("GROOTGeom", pNOTICE)
1377  << "SwimOnce x [" << r0[0] << "," << r0[1] << "," << r0[2]
1378  << "] udir [" << udir[0] << "," << udir[1] << "," << udir[2];
1379 #endif
1380 
1381  fGeometry -> SetCurrentDirection (udir[0],udir[1],udir[2]);
1382  fGeometry -> SetCurrentPoint (r0[0], r0[1], r0[2] );
1383 
1384  while (!found_vol || keep_on) {
1385  keep_on = true;
1386 
1387  fGeometry->FindNode();
1388 
1389  ps_curr.SetEnter( fGeometry->GetCurrentPoint() , raydist );
1390  vol = fGeometry->GetCurrentVolume();
1391  med = vol->GetMedium();
1392  mat = med->GetMaterial();
1393  ps_curr.SetGeo(vol,med,mat);
1394 #ifdef PATHSEG_KEEP_PATH
1395  if (fill_path) ps_curr.SetPath(fGeometry->GetPath());
1396 #endif
1397 
1398 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
1399 #ifdef DUMP_SWIM
1400  LOG("GROOTGeom", pDEBUG) << "Current volume: " << vol->GetName()
1401  << " pos " << fGeometry->GetCurrentPoint()[0]
1402  << " " << fGeometry->GetCurrentPoint()[1]
1403  << " " << fGeometry->GetCurrentPoint()[2]
1404  << " dir " << fGeometry->GetCurrentDirection()[0]
1405  << " " << fGeometry->GetCurrentDirection()[1]
1406  << " " << fGeometry->GetCurrentDirection()[2]
1407  << "[path: " << fGeometry->GetPath() << "]";
1408 #endif
1409 #endif
1410 
1411  // find the start of top
1412  if (fGeometry->IsOutside() || !vol) {
1413  keep_on = false;
1414  if (found_vol) break;
1415  step = 0;
1416  this->StepToNextBoundary();
1417  //rwh//raydist += step; // STNB doesn't actually "step"
1418 
1419 #ifdef RWH_DEBUG
1420 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
1421  LOG("GROOTGeom", pDEBUG) << "Outside ToNextBoundary step: " << step
1422  << " raydist: " << raydist;
1423 #endif
1424 #endif
1425 
1426  while (!fGeometry->IsEntering()) {
1427  step = this->Step();
1428  raydist += step;
1429 #ifdef RWH_DEBUG
1430 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
1431  LOG("GROOTGeom", pDEBUG)
1432  << "Stepping... [step size = " << step << "]";
1433  LOG("GROOTGeom", pDEBUG) << "Outside step: " << step
1434  << " raydist: " << raydist;
1435 #endif
1436 #endif
1437  if (this->WillNeverEnter(step)) {
1438 #ifdef RWH_COUNTVOLS
1439  if ( accum_vol_stat ) {
1440  // this really shouldn't happen for the box exploration...
1441  // if coord transforms done right
1442  // could happen for neutrinos on a flux window
1443  nnever[curface]++; //rwh
1444  if ( nnever[curface]%21 == 0 )
1445  LOG("GROOTGeom", pNOTICE)
1446  << "curface " << curface << " " << nswims[curface]
1447  << " never " << nnever[curface]
1448  << " x [" << r0[0] << "," << r0[1] << "," << r0[2] << "] "
1449  << " p [" << udir[0] << "," << udir[1] << "," << udir[2] << "]";
1450  }
1451 #endif
1453  return;
1454  }
1455  } // finished while
1456 
1457  ps_curr.SetExit(fGeometry->GetCurrentPoint());
1458  ps_curr.SetStep(step);
1459  if ( ( fDebugFlags & 0x10 ) ) {
1460  // In general don't add the path segments from the start point to
1461  // the top volume (here for debug purposes)
1462  // Clear out the step range even if we keep it
1463  ps_curr.fStepRangeSet.clear();
1464  LOG("GROOTGeom", pNOTICE)
1465  << "debug: step towards top volume: " << ps_curr;
1466  fCurrPathSegmentList->AddSegment(ps_curr);
1467  }
1468 
1469  } // outside or !vol
1470 
1471  if (keep_on) {
1472  if (!found_vol) found_vol = true;
1473 
1474  step = this->StepUntilEntering();
1475  raydist += step;
1476 
1477  ps_curr.SetExit(fGeometry->GetCurrentPoint());
1478  ps_curr.SetStep(step);
1479  fCurrPathSegmentList->AddSegment(ps_curr);
1480 
1481  nvolswim++; //rwh
1482 
1483 #ifdef DUMP_SWIM
1484  LOG("GROOTGeom", pDEBUG) << "Current volume: " << vol->GetName()
1485  << " step " << step << " in " << mat->GetName();
1486 #endif
1487 
1488 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
1489  LOG("GROOTGeom", pDEBUG)
1490  << "Cur med.: " << med->GetName() << ", mat.: " << mat->GetName();
1491  LOG("GROOTGeom", pDEBUG)
1492  << "Step = " << step; // << ", weight = " << weight;
1493 #endif
1494  } //keep on
1495  }
1496 
1497 #ifdef RWH_COUNTVOLS
1498  if ( accum_vol_stat ) {
1499  nswims[curface]++; //rwh
1500  dnvols[curface] += (double)nvolswim;
1501  dnvols2[curface] += (double)nvolswim * (double)nvolswim;
1502  long int ns = fCurrPathSegmentList->size();
1503  if ( ns > mxsegments ) mxsegments = ns;
1504  }
1505 #endif
1506 
1507 //rwh:debug
1508 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
1509  LOG("GROOTGeom", pDEBUG)
1510  << "PathSegmentList size " << fCurrPathSegmentList->size();
1511 #endif
1512 
1513 #ifdef RWH_DEBUG_2
1514  if ( ( fDebugFlags & 0x20 ) ) {
1516  LOG("GROOTGeom", pNOTICE) << "Before trimming" << *fCurrPathSegmentList;
1517  double mxddist = 0, mxdstep = 0;
1518  fCurrPathSegmentList->CrossCheck(mxddist,mxdstep);
1519  fmxddist = TMath::Max(fmxddist,mxddist);
1520  fmxdstep = TMath::Max(fmxdstep,mxdstep);
1521  }
1522 #endif
1523 
1524  // PathSegmentList trimming occurs here!
1525  if ( fGeomVolSelector ) {
1526  PathSegmentList* altlist =
1529  delete altlist; // after swap delete original
1530  }
1531 
1533 
1534 #ifdef RWH_DEBUG_2
1535  if ( fGeomVolSelector) {
1536  // after FillMatStepSum() so one can see the summed mass
1537  if ( ( fDebugFlags & 0x40 ) ) {
1539  LOG("GROOTGeom", pNOTICE) << "After trimming" << *fCurrPathSegmentList;
1541  }
1542  }
1543 #endif
1544 
1545 
1546  return;
1547 }
1548 
1549 //___________________________________________________________________________
1551 {
1552  TGeoVolume * vol = fGeometry -> GetCurrentVolume();
1553  if(vol) {
1554  TGeoMaterial * mat = vol->GetMedium()->GetMaterial();
1555  if(mat->IsMixture()) {
1556  TGeoMixture * mixt = dynamic_cast <TGeoMixture*> (mat);
1557  for(int i = 0; i < mixt->GetNelements(); i++) {
1558  int pdg = this->GetTargetPdgCode(mixt, i);
1559  if(tgtpdg == pdg) return true;
1560  }
1561  } else {
1562  int pdg = this->GetTargetPdgCode(mat);
1563  if(tgtpdg == pdg) return true;
1564  }
1565  } else {
1566  LOG("GROOTGeom", pWARN) << "Current volume is null!";
1567  return false;
1568  }
1569  return false;
1570 }
1571 //___________________________________________________________________________
1573 {
1574  fGeometry->FindNextBoundary();
1575  double step=fGeometry->GetStep();
1576  return step;
1577 }
1578 //___________________________________________________________________________
1580 {
1581  fGeometry->Step();
1582  double step=fGeometry->GetStep();
1583  return step;
1584 }
1585 //___________________________________________________________________________
1587 {
1588  this->StepToNextBoundary(); // doesn't actually step, so don't include in sum
1589  double step = 0; //
1590 
1591  while(!fGeometry->IsEntering()) {
1592  step += this->Step();
1593  }
1594 
1595 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
1596 
1597  bool isen = fGeometry->IsEntering();
1598  bool isob = fGeometry->IsOnBoundary();
1599 
1600  LOG("GROOTGeom",pDEBUG)
1601  << "IsEntering = " << utils::print::BoolAsYNString(isen)
1602  << ", IsOnBoundary = " << utils::print::BoolAsYNString(isob)
1603  << ", Step = " << step;
1604 #endif
1605 
1606  return step;
1607 }
1608 //___________________________________________________________________________
1610 {
1611 // If the neutrino trajectory would never enter the detector, then the
1612 // TGeoManager::GetStep returns the maximum step (1E30).
1613 // Compare surrent step with max step and figure out whether the particle
1614 // would never enter the detector
1615 
1616  if (step > 9.99E29) {
1617 
1618 #ifdef __GENIE_LOW_LEVEL_MESG_ENABLED__
1619  LOG("GROOTGeom", pINFO) << "Wow! Current step is dr = " << step;
1620  LOG("GROOTGeom", pINFO) << "This trajectory isn't entering the detector";
1621 #endif
1622  return true;
1623 
1624  } else
1625  return false;
1626 }
1627 
1628 //___________________________________________________________________________
static QCString name
Definition: declinfo.cpp:673
virtual double MaxEnergy(void)=0
declare the max flux neutrino energy that can be generated (for init. purposes)
void ScalePathLength(int pdgc, double scale)
virtual int ScannerNParticles(void) const
virtual void SetMaxPlSafetyFactor(double sf)
intermediate_table::iterator iterator
TGeoManager * fGeometry
input detector geometry
double PathLength(int pdgc) const
void SetEnter(const TVector3 &p3enter, double raydist)
point of entry to geometry element
virtual double GetWeight(const TGeoMaterial *mat, int pdgc)
void SetPrintVerbose(bool doit=true)
string P4AsShortString(const TLorentzVector *p)
Definition: PrintUtils.cxx:45
virtual bool WeightWithDensity(void) const
virtual const PathLengthList & ComputeMaxPathLengths(void)
THE MAIN GENIE PROJECT NAMESPACE
Definition: AlgCmp.h:25
#define pERROR
Definition: Messenger.h:59
double rms(sqlite3 *db, std::string const &table_name, std::string const &column_name)
Definition: statistics.cc:40
static RandomGen * Instance()
Access instance.
Definition: RandomGen.cxx:71
void CrossCheck(double &mxddist, double &mxdstep) const
void SetPath(const char *path)
string BoolAsYNString(bool b)
Definition: PrintUtils.cxx:108
StepRangeSet fStepRangeSet
collection of {steplo,stephi} pairs
bool fDensWeight
if true pathlengths are weighted with density [def:true]
#define pFATAL
Definition: Messenger.h:56
virtual const TLorentzVector & Position(void)=0
returns the flux neutrino 4-position (note: expect SI rather than physical units) ...
void AddSegment(const PathSegment &ps)
GFluxI * fFlux
a flux objects that can be used to scan the max path lengths
static const std::string volume[nvol]
string P3AsString(const TVector3 *vec)
Definition: PrintUtils.cxx:69
xmlNodePtr FindNode(xmlDocPtr xml_doc, string node_path)
virtual void Top2Master(TVector3 &v) const
GENIE geometry drivers.
double fLengthScale
conversion factor: input geometry length units -> meters
Object to be filled with the neutrino path-segments representing geometry volume steps (generally bou...
void SetPathLength(int pdgc, double pl)
bool ExistsInPDGCodeList(int pdg_code) const
int fNRays
max path length scanner (box method): rays/point [def:200]
intermediate_table::const_iterator const_iterator
TVector3 * fCurrVertex
current generated vertex
bool IsSameStart(const TVector3 &pos, const TVector3 &dir) const
double fMaxPlSafetyFactor
factor that can multiply the computed max path lengths
virtual void SetScannerNParticles(int np)
string fTopVolumeName
input top vol [other than TGeoManager::GetTopVolume()]
void SetStep(Double_t step, bool setlimits=true)
step taken in the geometry element
string filename
Definition: train.py:213
A singleton holding random number generator classes. All random number generation in GENIE should tak...
Definition: RandomGen.h:29
virtual void SetDensityUnits(double du)
virtual const PDGCodeList & ListOfTargetNuclei(void)
implement the GeomAnalyzerI interface
weight
Definition: test.py:257
virtual bool FindMaterialInCurrentVol(int pdgc)
A list of PDG codes.
Definition: PDGCodeList.h:32
virtual double MixtureWeightsSum(void) const
virtual const PathLengthList & ComputePathLengths(const TLorentzVector &x, const TLorentzVector &p)
bool exists(std::string path)
Object to be filled with the neutrino path-length, for all detector geometry materials, when starting from a position x and travelling along the direction of the neutrino 4-momentum.
const TGeoMaterial * fMaterial
ref only ptr to TGeoMaterial
T abs(T value)
virtual int GetTargetPdgCode(const TGeoMaterial *const m) const
double foz
top vol size/origin (top vol units)
double fDensityScale
conversion factor: input geometry density units -> kgr/meters^3
#define LOG(stream, priority)
A macro that returns the requested log4cpp::Category appending a string (using the FILE...
Definition: Messenger.h:96
static constexpr double kilogram
Definition: Units.h:36
int fNPoints
max path length scanner (box method): points/surface [def:200]
PathSegmentV_t::const_iterator PathSegVCItr_t
void swap(Handle< T > &a, Handle< T > &b)
virtual bool GenBoxRay(int indx, TLorentzVector &x4, TLorentzVector &p4)
virtual double LengthUnits(void) const
virtual void SetScannerNRays(int nr)
#define Import
static constexpr double meter3
Definition: Units.h:51
const TGeoVolume * fVolume
ref only ptr to TGeoVolume
PDGCodeList * fCurrPDGCodeList
current list of target nuclei
virtual void SetWeightWithDensity(bool wt)
PathSegmentList * fCurrPathSegmentList
current list of path-segments
PathLengthList * fCurrMaxPathLengthList
current list of max path-lengths
p
Definition: test.py:223
void SetStartInfo(const TVector3 &pos=TVector3(0, 0, 1e37), const TVector3 &dir=TVector3(0, 0, 0))
virtual void Load(string geometry_filename)
#define pINFO
Definition: Messenger.h:62
Double_t GetSummedStepRange() const
get the sum of all the step range (in case step has been trimmed or split)
TRandom3 & RndGeom(void) const
rnd number generator used by geometry drivers
Definition: RandomGen.h:68
virtual double ComputePathLengthPDG(const TVector3 &r, const TVector3 &udir, int pdgc)
virtual void Local2SI(PathLengthList &pl) const
access to geometry coordinate/unit transforms for validation/test purposes
GeomVolSelectorI * fGeomVolSelector
optional path seg trimmer (owned)
const PathSegmentV_t & GetPathSegmentV(void) const
double fmxdstep
max errors in pathsegmentlist
Misc GENIE control constants.
#define pWARN
Definition: Messenger.h:60
virtual double DensityUnits(void) const
virtual void Master2TopDir(TVector3 &v) const
virtual void Clear(Option_t *opt)=0
reset state variables based on opt
virtual bool GenerateNext(void)=0
generate the next flux neutrino (return false in err)
virtual const TVector3 & GenerateVertex(const TLorentzVector &x, const TLorentzVector &p, int tgtpdg)
bool GetNeedPath() const
allow toggle on only
MaterialMap_t::const_iterator MaterialMapCItr_t
void SetCurrentRay(const TLorentzVector &x4, const TLorentzVector &p4)
configure for individual neutrino ray
PathLengthList * fCurrPathLengthList
current list of path-lengths
virtual PathSegmentList * GenerateTrimmedList(const PathSegmentList *untrimmed) const
static constexpr double meter
Definition: Units.h:35
virtual void SetTopVolName(string nm)
void SetDoCrossCheck(bool doit=true)
TGeoHMatrix * fMasterToTop
matrix connecting master coordinates to top volume coordinates
bool fMasterToTopIsIdentity
is fMasterToTop matrix the identity matrix?
void SetGeo(const TGeoVolume *gvol, const TGeoMedium *gmed, const TGeoMaterial *gmat)
info about the geometry element
std::map< const TGeoMaterial *, Double_t > MaterialMap_t
TVector3 GetPosition(Double_t frac) const
calculate position within allowed ranges passed on fraction of total
virtual void SetScannerNPoints(int np)
set geometry driver&#39;s configuration options
virtual void SetScannerFlux(GFluxI *f)
const MaterialMap_t & GetMatStepSumMap(void) const
virtual void SetMixtureWeightsSum(double sum)
int IonPdgCode(int A, int Z)
Definition: PDGUtils.cxx:68
virtual const TLorentzVector & Momentum(void)=0
returns the flux neutrino 4-momentum
void SetExit(const TVector3 &p3exit)
point of exit from geometry element
TGeoVolume * fTopVolume
top volume
#define A
Definition: memgrp.cpp:38
list x
Definition: train.py:276
virtual double MaxPlSafetyFactor(void) const
virtual void SetLengthUnits(double lu)
void AddPathLength(int pdgc, double pl)
virtual void Top2MasterDir(TVector3 &v) const
double fMixtWghtSum
norm of relative weights (<0 if explicit summing required)
#define pNOTICE
Definition: Messenger.h:61
Defines the GENIE Geometry Analyzer Interface.
Definition: GeomAnalyzerI.h:29
string X4AsString(const TLorentzVector *x)
Definition: PrintUtils.cxx:57
virtual void SI2Local(TVector3 &v) const
bool fKeepSegPath
need to fill path segment "path"
std::list< PathSegment > PathSegmentV_t
QAsciiDict< Entry > ns
string Vec3AsString(const TVector3 *vec)
Definition: PrintUtils.cxx:80
void SetSI2Local(double scale)
set scale factor for SI to "raydist" units of PathSegmentList
virtual void SwimOnce(const TVector3 &r, const TVector3 &udir)
virtual void Master2Top(TVector3 &v) const
void push_back(int pdg_code)
Definition: PDGCodeList.cxx:58
#define pDEBUG
Definition: Messenger.h:63
virtual bool WillNeverEnter(double step)