Belle II Software  release-05-02-19
MaterialScan.cc
1 /**************************************************************************
2  * BASF2 (Belle Analysis Framework 2) *
3  * Copyright(C) 2010-2018 Belle II Collaboration *
4  * *
5  * Author: The Belle II Collaboration *
6  * Contributors: Martin Ritter *
7  * *
8  * This software is provided "as is" without any warranty. *
9  **************************************************************************/
10 
11 #include <simulation/modules/MaterialScan.h>
12 #include <framework/core/ModuleParam.templateDetails.h>
13 #include <framework/gearbox/Unit.h>
14 #include <framework/utilities/Utils.h>
15 #include <algorithm>
16 
17 #include <TFile.h>
18 #include <TH1D.h>
19 #include <TH2D.h>
20 #include <TRandom.h>
21 
22 #include <G4Event.hh>
23 #include <G4EventManager.hh>
24 #include <G4UserEventAction.hh>
25 #include <G4UserStackingAction.hh>
26 #include <G4UserTrackingAction.hh>
27 #include <G4UserSteppingAction.hh>
28 #include <G4RayShooter.hh>
29 #include <G4Track.hh>
30 
31 #include <boost/format.hpp>
32 #include <boost/algorithm/string.hpp>
33 
34 using namespace std;
35 using namespace Belle2;
36 
37 //-----------------------------------------------------------------
38 // Register the Module
39 //-----------------------------------------------------------------
40 REG_MODULE(MaterialScan);
41 
42 //-----------------------------------------------------------------
43 // Implementation
44 //-----------------------------------------------------------------
45 
46 bool MaterialScanBase::checkStep(const G4Step* step)
47 {
48  double stlen = step->GetStepLength();
49  G4StepPoint* preStepPoint = step->GetPreStepPoint();
50  G4Region* region = preStepPoint->GetPhysicalVolume()->GetLogicalVolume()->GetRegion();
51  if (stlen < c_zeroTolerance) {
52  ++m_zeroSteps;
53  } else {
54  m_zeroSteps = 0;
55  }
56  if (m_zeroSteps > c_maxZeroStepsNudge) {
57  if (m_zeroSteps > c_maxZeroStepsKill) {
58  B2ERROR("Track is stuck at " << preStepPoint->GetPosition() << " in volume '"
59  << preStepPoint->GetPhysicalVolume()->GetLogicalVolume()->GetName()
60  << " (" << region->GetName() << "): "
61  << m_zeroSteps << " consecutive steps with length less then "
62  << c_zeroTolerance << " mm, killing it");
63  step->GetTrack()->SetTrackStatus(fStopAndKill);
64  } else {
65  B2WARNING("Track is stuck at " << preStepPoint->GetPosition() << " in volume '"
66  << preStepPoint->GetPhysicalVolume()->GetLogicalVolume()->GetName()
67  << " (" << region->GetName() << "): "
68  << m_zeroSteps << " consecutive steps with length less then "
69  << c_zeroTolerance << " mm, nudging it along");
70  G4ThreeVector pos = step->GetTrack()->GetPosition();
71  G4ThreeVector dir = step->GetTrack()->GetMomentumDirection();
72  step->GetTrack()->SetPosition(pos + c_zeroTolerance * dir);
73  }
74  return false;
75  }
76  return true;
77 }
78 
79 
80 MaterialScan2D::MaterialScan2D(TFile* rootFile, const std::string& name, const std::string& axisLabel, const ScanParams& params):
81  MaterialScanBase(rootFile, name, axisLabel), m_params(params), m_curDepth(0)
82 {
83  //Sort the parameters accordingly
84  if (m_params.minU > m_params.maxU) std::swap(m_params.minU, m_params.maxU);
85  if (m_params.minV > m_params.maxV) std::swap(m_params.minV, m_params.maxV);
86  //Calculate step size of the parameters
89  //Set Start values
90  m_curU = m_params.minU - m_stepU / 2.;
91  m_curV = m_params.minV + m_stepV / 2.;
92  //Convert max depth to G4 units
94  //Sort the list of ignored materials so that we can use binary search
95  std::sort(m_params.ignoredMaterials.begin(), m_params.ignoredMaterials.end());
96 }
97 
98 
99 bool MaterialScan2D::createNext(G4ThreeVector& origin, G4ThreeVector& direction)
100 {
101  if (m_regions.empty()) {
102  // create summary histogram right now, not on demand, to make sure it is in the file
104  getHistogram("All_Materials_x0");
105  getHistogram("All_Materials_lambda");
106  } else {
107  getHistogram("All_Regions_x0");
108  getHistogram("All_Regions_lambda");
109  }
110  }
111  //Increase the internal coordinates
112  m_curU += m_stepU;
113  if (m_curU >= m_params.maxU) {
114  m_curU = m_params.minU + m_stepU / 2.;
115  m_curV += m_stepV;
116  }
117  //Reset depth counter
118  m_curDepth = 0;
119 
120  //Get the origin and direction of the ray
121  getRay(origin, direction);
122 
123  //Check wether we are finished
124  return (m_curV <= m_params.maxV);
125 }
126 
127 TH2D* MaterialScan2D::getHistogram(const std::string& name)
128 {
129  std::unique_ptr<TH2D>& hist = m_regions[name];
130  if (!hist) {
131  //Create new histogram
132  m_rootFile->cd(m_name.c_str());
133  hist.reset(new TH2D(name.c_str(), (name + ";" + m_axisLabel).c_str(),
136  }
137  return hist.get();
138 }
139 
140 void MaterialScan2D::fillValue(const std::string& name, double value)
141 {
142  TH2D* hist = getHistogram(name);
143  hist->Fill(m_curU, m_curV, value);
144 }
145 
146 void MaterialScan2D::UserSteppingAction(const G4Step* step)
147 {
148  //Get information about radiation and interaction length
149  G4StepPoint* preStepPoint = step->GetPreStepPoint();
150  G4Region* region = preStepPoint->GetPhysicalVolume()->GetLogicalVolume()->GetRegion();
151  G4Material* material = preStepPoint->GetMaterial();
152  double stlen = step->GetStepLength();
153  double x0 = stlen / (material->GetRadlen());
154  double lambda = stlen / (material->GetNuclearInterLength());
155  B2DEBUG(20, "Step in at " << preStepPoint->GetPosition() << " in volume '"
156  << preStepPoint->GetPhysicalVolume()->GetLogicalVolume()->GetName()
157  << " (" << region->GetName() << ")"
158  << " with length=" << stlen << " mm");
159  checkStep(step);
160 
161  //check if the depth is limited
162  if (m_params.maxDepth > 0) {
163  m_curDepth += stlen;
164  if (m_curDepth > m_params.maxDepth) {
165  //Depth reached, kill track and add remaining part of the material budget
166  G4Track* track = step->GetTrack();
167  track->SetTrackStatus(fStopAndKill);
168  double remaining = stlen - m_curDepth + m_params.maxDepth;
169  x0 *= remaining / stlen;
170  lambda *= remaining / stlen;
171  }
172  }
173 
174  if (std::binary_search(m_params.ignoredMaterials.begin(), m_params.ignoredMaterials.end(), material->GetName())) {
175  return;
176  }
177 
178  //Fill x0 and lambda in a histogram for each region
179  string x0_total = "All_Regions_x0";
180  string lambda_total = "All_Regions_lambda";
181  string x0_name = region->GetName() + "_x0";
182  string lambda_name = region->GetName() + "_lambda";
183  //or for each Material
185  x0_total = "All_Materials_x0";
186  lambda_total = "All_Materials_lambda";
187  x0_name = material->GetName() + "_x0";
188  lambda_name = material->GetName() + "_lambda";
189  }
190  fillValue(x0_total, x0);
191  fillValue(lambda_total, lambda);
192  fillValue(x0_name, x0);
193  fillValue(lambda_name, lambda);
194 }
195 
196 void MaterialScanSpherical::getRay(G4ThreeVector& origin, G4ThreeVector& direction)
197 {
198  //We always shoot from the origin
199  origin = m_origin;
200  double theta = m_curU * Unit::deg;
201  double phi = m_curV * Unit::deg;
202  if (m_doCosTheta) {
203  theta = acos(m_curU);
204  }
205  direction.set(sin(theta) * cos(phi),
206  sin(theta) * sin(phi),
207  cos(theta));
208 }
209 
210 void MaterialScanPlanar::getRay(G4ThreeVector& origin, G4ThreeVector& direction)
211 {
212  //We shoot perpendicular to the plane, so direction is always the same but the position varies.
213  origin = m_origin + m_curU / Unit::mm * m_dirU + m_curV / Unit::mm * m_dirV;
214  direction = m_dirW;
215 }
216 
217 bool MaterialScanRay::createNext(G4ThreeVector& origin, G4ThreeVector& direction)
218 {
219  if (m_curRay > m_count) return false;
220 
221  origin = m_origin;
222  direction = m_dir;
223  ++m_curRay;
224  if (m_curRay == 0) {
225  // First ray is just to check what the maximum flight length is
226  return true;
227  } else if (m_curRay == 1) {
228  // this is the second ray, save the maximum depth for histograms
230  B2INFO("Set maximum depth to " << m_maxDepth);
231  // create summary histogram right now, not on demand, to make sure it is in the file
232  if (m_splitByMaterials) {
233  getHistogram("All_Materials_x0");
234  getHistogram("All_Materials_lambda");
235  } else {
236  getHistogram("All_Regions_x0");
237  getHistogram("All_Regions_lambda");
238  }
239  }
240  m_curDepth = 0;
241  if (m_opening > 0) {
242  // add small angle to the ray where we want the opening angle to be covered
243  // uniform by area so choose an angle uniform in cos(angle). We take half
244  // the opening angle because it can go in both sides
245  double theta = acos(gRandom->Uniform(cos(m_opening / 2.), 1));
246  double phi = gRandom->Uniform(0, 2 * M_PI);
247  auto orthogonal = direction.orthogonal();
248  orthogonal.rotate(phi, direction);
249  direction.rotate(theta, orthogonal);
250  }
251  B2DEBUG(10, "Create Ray " << m_curRay << " from " << origin << " direction " <<
252  direction << " [theta=" << (direction.theta() / M_PI * 180) << ", phi=" << (direction.phi() / M_PI * 180) << "]");
253  return true;
254 }
255 
256 TH1D* MaterialScanRay::getHistogram(const std::string& name)
257 {
258  std::unique_ptr<TH1D>& hist = m_regions[name];
259  if (!hist) {
260  //Create new histogram
261  m_rootFile->cd(m_name.c_str());
262  int bins = std::ceil(m_maxDepth / m_sampleDepth);
263  hist.reset(new TH1D(name.c_str(), (name + ";" + m_axisLabel).c_str(), bins, 0, m_maxDepth * Unit::mm));
264  }
265  return hist.get();
266 }
267 
268 void MaterialScanRay::fillValue(const std::string& name, double value, double steplength)
269 {
270  TH1D* h = getHistogram(name);
271  double x = m_curDepth;
272  //The steps are not aligned to the bin sizes so make sure we sub-sample the
273  //value and put it in the histogram in smaller steps. We choose 10 samples
274  //per bin here which should be good enough.
275  int samples = std::ceil(steplength / m_sampleDepth * 10);
276  const double dx = steplength / samples;
277  const double dv = value / samples / m_count / h->GetBinWidth(1);
278  for (int i = 0; i < samples; ++i) {
279  h->Fill(x * Unit::mm, dv);
280  x += dx;
281  }
282 }
283 
284 void MaterialScanRay::UserSteppingAction(const G4Step* step)
285 {
286  //Get information about radiation and interaction length
287  G4StepPoint* preStepPoint = step->GetPreStepPoint();
288  G4Region* region = preStepPoint->GetPhysicalVolume()->GetLogicalVolume()->GetRegion();
289  G4Material* material = preStepPoint->GetMaterial();
290  const bool ignored = m_ignoredMaterials.count(material->GetName()) > 0;
291  double stlen = step->GetStepLength();
292  double x0 = stlen / (material->GetRadlen());
293  double lambda = stlen / (material->GetNuclearInterLength());
294  B2DEBUG(20, "Step in at " << preStepPoint->GetPosition() << " in volume '"
295  << preStepPoint->GetPhysicalVolume()->GetLogicalVolume()->GetName()
296  << " (" << region->GetName() << ")"
297  << " with length=" << stlen << " mm");
298  checkStep(step);
299 
300  //check if the depth is limited
301  if (m_maxDepth > 0) {
302  if (m_curDepth + stlen > m_maxDepth) {
303  //Depth reached, kill track and add remaining part of the material budget
304  G4Track* track = step->GetTrack();
305  track->SetTrackStatus(fStopAndKill);
306  double remaining = m_maxDepth - m_curDepth;
307  x0 *= remaining / stlen;
308  lambda *= remaining / stlen;
309  stlen = remaining;
310  }
311  }
312 
313  if (m_curRay > 0 && !ignored) {
314  //Fill x0 and lambda in a histogram for each region
315  string x0_total = "All_Regions_x0";
316  string lambda_total = "All_Regions_lambda";
317  string x0_name = region->GetName() + "_x0";
318  string lambda_name = region->GetName() + "_lambda";
319  //or for each Material
320  if (m_splitByMaterials) {
321  x0_total = "All_Materials_x0";
322  lambda_total = "All_Materials_lambda";
323  x0_name = material->GetName() + "_x0";
324  lambda_name = material->GetName() + "_lambda";
325  }
326  fillValue(x0_total, x0, stlen);
327  fillValue(lambda_total, lambda, stlen);
328  fillValue(x0_name, x0, stlen);
329  fillValue(lambda_name, lambda, stlen);
330  }
331  m_curDepth += stlen;
332  if (m_curRay == 0 && !ignored) {
333  // update max depth only for materials we do not ignore ...
335  }
336 }
337 
338 MaterialScanModule::MaterialScanModule(): m_rootFile(0), m_sphericalOrigin(3, 0), m_doCosTheta(false)
339 {
340  //Set module properties
341  setDescription("This Module is intended to scan the material budget of the "
342  "geometry. Currently, there are two different kinds of scans "
343  "available: Spherical and Planar scan. \n"
344  "Spherical scan will shoot rays from the origin of the "
345  "detector and scan along the polar and azimuth angle.\n"
346  "Planar scan will shoot rays perpendicular to a given "
347  "plane.");
348 
349  //Set default ignored Materials
350  m_spherical.ignoredMaterials.push_back("Vacuum");
351  m_spherical.ignoredMaterials.push_back("Air");
352  m_spherical.ignoredMaterials.push_back("G4_AIR");
353  m_planar.ignoredMaterials = m_spherical.ignoredMaterials;
354  m_rayIgnoredMaterials = m_spherical.ignoredMaterials;
355 
356  addParam("Filename", m_filename,
357  "The filename where the material scan will be stored",
358  string("MaterialScan.root"));
359  addParam("spherical", m_doSpherical,
360  "Do a spherical scan, that is shooting rays from the origin with "
361  "varying angles", true);
362  addParam("spherical.origin", m_sphericalOrigin,
363  "Origin for the spherical scan", m_sphericalOrigin);
364  addParam("spherical.nTheta", m_spherical.nU,
365  "Number of rays in theta", 200);
366  addParam("spherical.minTheta", m_spherical.minU,
367  "Theta start angle", 17.);
368  addParam("spherical.maxTheta", m_spherical.maxU,
369  "Theta stop angle", 150.);
370  addParam("spherical.nPhi", m_spherical.nV,
371  "Number of rays in phi", 200);
372  addParam("spherical.minPhi", m_spherical.minV,
373  "Phi start angle", 0.);
374  addParam("spherical.maxPhi", m_spherical.maxV,
375  "Phi stop angle", 360.);
376  addParam("spherical.maxDepth", m_spherical.maxDepth,
377  "Maximum scan depth in cm. The ray will be killed after having "
378  "reached the maximum Depth. <=0 means no Limit.", -1.0);
379  addParam("spherical.ignored", m_spherical.ignoredMaterials,
380  "Names of Materials which should be ignored when doing the scan", m_spherical.ignoredMaterials);
381  addParam("spherical.splitByMaterials", m_spherical.splitByMaterials,
382  "If True, split output by material names instead of by regions", false);
383  addParam("spherical.cosTheta", m_doCosTheta,
384  "If True, perform the spherical scan uniform in cos(theta) instead of theta", false);
385 
386  addParam("planar", m_doPlanar,
387  "Do a plane scan, that is shooting parallel rays from a defined "
388  "plane", true);
389  addParam("planar.plane", m_planeName,
390  "Plane to use for scanning, available are all two letter "
391  "combinations of X,Y and Z like XY and XZ and custom", string("ZX"));
392  addParam("planar.nU", m_planar.nU,
393  "Number of rays in U", 200);
394  addParam("planar.minU", m_planar.minU,
395  "U start", -400.0);
396  addParam("planar.maxU", m_planar.maxU,
397  "U stop", 400.0);
398  addParam("planar.nV", m_planar.nV,
399  "Number of rays in V", 200);
400  addParam("planar.minV", m_planar.minV,
401  "V start", -400.0);
402  addParam("planar.maxV", m_planar.maxV,
403  "V stop", 400.0);
404  addParam("planar.maxDepth", m_planar.maxDepth,
405  "Maximum scan depth in cm. The ray will be killed after having "
406  "reached the maximum Depth. <=0 means no Limit.", -1.0);
407  addParam("planar.custom", m_customPlane,
408  "Parameters of the plane when choosing custom. This is supposed to "
409  "be a list of 9 values: The first three are the coordinates of the "
410  "plane origin. The second three are the direction of U in the "
411  "r-phi coordinates. The last three are the direction of V in the "
412  "coordinates parallel to the detector axis (beamline). ", m_customPlane);
413  addParam("planar.ignored", m_planar.ignoredMaterials,
414  "Names of Materials which should be ignored when doing the scan", m_planar.ignoredMaterials);
415  addParam("planar.splitByMaterials", m_planar.splitByMaterials,
416  "If True, split output by material names instead of by regions", false);
417 
418  addParam("ray", m_doRay, "Do a ray scan: Shoot from the given origin in a "
419  "given direction and record the material encountered along the way", false);
420  addParam("ray.origin", m_rayOrigin, "Origin for the ray", m_rayOrigin);
421  addParam("ray.theta", m_rayTheta, "Theta angle for the ray in degrees", m_rayTheta);
422  addParam("ray.phi", m_rayPhi, "Phi angle of the ray in degrees", m_rayPhi);
423  addParam("ray.direction", m_rayDirection, "Set the ray direction as vector "
424  "[x,y,z]. You cannot set this and theta/phi at the same time",
425  m_rayDirection);
426  addParam("ray.opening", m_rayOpening, "Opening angle for the ray in degrees. "
427  "If bigger than 0 then multiple rays (``ray.count``) will be shot "
428  "randomly inside the opening angle uniformly distributed in area "
429  "(cosine of the angle)", m_rayOpening);
430  addParam("ray.count", m_rayCount, "Count of rays if the opening angle is >0",
431  m_rayCount);
432  addParam("ray.sampleDepth", m_raySampleDepth, "Distance in which to sample the "
433  "material", m_raySampleDepth);
434  addParam("ray.maxDepth", m_rayMaxDepth, "Max distance for the ray before it's "
435  "stopped, 0 for no limit. The actual depth can be smaller if the "
436  "simulation volume ends earlier", m_rayMaxDepth);
437  addParam("ray.ignored", m_rayIgnoredMaterials, "Names of Materials which "
438  "should be ignored when doing the scan", m_rayIgnoredMaterials);
439 }
440 
442 {
443  m_rootFile = TFile::Open(m_filename.c_str(), "RECREATE");
444  if (!m_rootFile || m_rootFile->IsZombie()) {
445  B2ERROR("Cannot open rootfile for writing" << LogVar("rootfile", m_filename));
446  return;
447  }
448 
449  boost::to_lower(m_planeName);
450  boost::trim(m_planeName);
451  //Check if plane definition makes sense
452  if (m_planeName == "custom") {
453  if (m_customPlane.size() < 9) {
454  B2ERROR("planar.custom: At least 9 values needed to define custom plane, only " << m_customPlane.size() << " provided");
455  }
456  } else if (m_planeName.size() != 2 || !boost::all(m_planeName, boost::is_any_of("xyz"))) {
457  B2ERROR("planar.plane: Only custom or any two letter combinations of X,Y and Z are recognized");
458  } else if (m_planeName[0] == m_planeName[1]) {
459  B2ERROR("planar.plane: " << m_planeName << " not valid, cannot use the same axis twice");
460  }
461 
462  //Check if we have enough values to define the origin
463  if (m_sphericalOrigin.size() < 3) {
464  B2ERROR("spherical.origin: Three values are needed to define a point, only " << m_sphericalOrigin.size() << " given.");
465  }
466 
467  //Convert plane definition to mm since Geant4 is of course using other units
468  for (double& value : m_customPlane) value /= Unit::mm;
469  for (double& value : m_sphericalOrigin) value /= Unit::mm;
470  for (double& value : m_rayOrigin) value /= Unit::mm;
471  if (m_rayDirection) {
472  if (getParam<double>("ray.theta").isSetInSteering() || getParam<double>("ray.phi").isSetInSteering()) {
473  B2ERROR("Cannot set ray.theta/ray.phi and ray.direction at the same time, please only set one");
474  return;
475  }
476  for (double& value : *m_rayDirection) value /= Unit::mm;
477  }
478 }
479 
481 {
482  G4EventManager* eventManager = G4EventManager::GetEventManager();
483 
484  //First we save all user actions
485  G4UserEventAction* vanillaEventAction = eventManager->GetUserEventAction();
486  G4UserStackingAction* vanillaStackingAction = eventManager->GetUserStackingAction();
487  G4UserTrackingAction* vanillaTrackingAction = eventManager->GetUserTrackingAction();
488  G4UserSteppingAction* vanillaSteppingAction = eventManager->GetUserSteppingAction();
489 
490  //Then we clear the user actions
491  eventManager->SetUserAction((G4UserEventAction*)0);
492  eventManager->SetUserAction((G4UserStackingAction*)0);
493  eventManager->SetUserAction((G4UserTrackingAction*)0);
494 
495  //We create our own stepping actions which will
496  //- create the vectors for shooting rays
497  //- record the material budget for each ray
498  vector<MaterialScanBase*> scans;
499  if (m_doSpherical) {
500  G4ThreeVector origin(m_sphericalOrigin[0], m_sphericalOrigin[1], m_sphericalOrigin[2]);
501  scans.push_back(new MaterialScanSpherical(m_rootFile, origin, m_spherical, m_doCosTheta));
502  }
503  if (m_doPlanar) {
504  G4ThreeVector origin(0, 0, 0);
505  G4ThreeVector uDir;
506  G4ThreeVector vDir;
507  if (m_planeName == "custom") {
508  origin.set(m_customPlane[0], m_customPlane[1], m_customPlane[2]);
509  uDir.set(m_customPlane[3], m_customPlane[4], m_customPlane[5]);
510  vDir.set(m_customPlane[6], m_customPlane[7], m_customPlane[8]);
511  } else {
512  uDir = getAxis(m_planeName[0]);
513  vDir = getAxis(m_planeName[1]);
514  }
515  scans.push_back(new MaterialScanPlanar(m_rootFile, origin, uDir, vDir, m_planar));
516  }
517 
518  if (m_doRay) {
519  G4ThreeVector origin(m_sphericalOrigin[0], m_sphericalOrigin[1], m_sphericalOrigin[2]);
520  G4ThreeVector dir;
521  if (m_rayDirection) {
522  for (int i = 0; i < 3; ++i) dir[0] = (*m_rayDirection)[0];
523  dir = dir.unit();
524  } else {
525  dir.setRThetaPhi(1., m_rayTheta * Unit::deg, m_rayPhi * Unit::deg);
526  }
527  scans.push_back(new MaterialScanRay(m_rootFile, origin, dir, m_rayOpening * Unit::deg, m_rayCount,
530  }
531 
532  //Do each configured scan
533  for (MaterialScanBase* scan : scans) {
534  //Set the Scan as steppingaction to see material
535  eventManager->SetUserAction(scan);
536  //Now we can scan
537  G4RayShooter rayShooter;
538  G4ThreeVector origin;
539  G4ThreeVector direction;
540  int maxRays = scan->getNRays();
541  int curRay(0);
542  int lastPercent(-1);
543  double start = Utils::getClock();
544  //Create one event per ray and process it
545  while (scan->createNext(origin, direction)) {
546  G4Event* event = new G4Event(++curRay);
547  rayShooter.Shoot(event, origin, direction);
548  eventManager->ProcessOneEvent(event);
549  delete event;
550 
551  //Show progress
552  int donePercent = 100 * curRay / maxRays;
553  if (donePercent > lastPercent) {
554  double perRay = (Utils::getClock() - start) / curRay;
555  double eta = perRay * (maxRays - curRay);
556  B2INFO(boost::format("%s Scan: %3d%%, %.3f ms per ray, ETA: %.2f seconds")
557  % scan->getName() % donePercent
558  % (perRay / Unit::ms) % (eta / Unit::s));
559  lastPercent = donePercent;
560  }
561  }
562  }
563  m_rootFile->Write();
564  // free the scan objects which also deletes the histograms ...
565  for (MaterialScanBase* scan : scans) {
566  delete scan;
567  }
568  // and delete the file, which we could not do before because that would also delete the histograms ...
569  m_rootFile->Close();
570  delete m_rootFile;
571  m_rootFile = nullptr;
572  //And now we reset the user actions
573  eventManager->SetUserAction(vanillaEventAction);
574  eventManager->SetUserAction(vanillaStackingAction);
575  eventManager->SetUserAction(vanillaTrackingAction);
576  eventManager->SetUserAction(vanillaSteppingAction);
577 }
578 
579 G4ThreeVector MaterialScanModule::getAxis(char name)
580 {
581  switch (name) {
582  case 'x': return G4ThreeVector(1, 0, 0);
583  case 'y': return G4ThreeVector(0, 1, 0);
584  case 'z': return G4ThreeVector(0, 0, 1);
585  default:
586  B2FATAL("Unknown axis: " << name);
587  }
588  return G4ThreeVector(0, 0, 0);
589 }
Belle2::Unit::s
static const double s
[second]
Definition: Unit.h:105
Belle2::MaterialScanModule::m_doRay
bool m_doRay
Perform a material ray scan: scan along a certain direction with a given opening angle and plot mater...
Definition: MaterialScan.h:373
Belle2::MaterialScan2D::getHistogram
TH2D * getHistogram(const std::string &name)
get histogram for a given name, create if needed.
Definition: MaterialScan.cc:127
Belle2::MaterialScanRay::m_opening
double m_opening
Opening angle in radian.
Definition: MaterialScan.h:283
Belle2::MaterialScan2D::fillValue
void fillValue(const std::string &name, double value)
Fill the recorded material budget into the corresponding histogram.
Definition: MaterialScan.cc:140
Belle2::Unit::ms
static const double ms
[millisecond]
Definition: Unit.h:106
Belle2::MaterialScanModule::m_raySplitByMaterials
bool m_raySplitByMaterials
If true Split by materials instead of regions when doing ray scan.
Definition: MaterialScan.h:375
Belle2::MaterialScan2D::getRay
virtual void getRay(G4ThreeVector &origin, G4ThreeVector &direction)=0
Get the origin and direction for the next scan particle.
Belle2::MaterialScanRay::m_regions
std::map< std::string, std::unique_ptr< TH1D > > m_regions
Map holding pointers to all created histograms.
Definition: MaterialScan.h:277
Belle2::MaterialScanModule::m_rayMaxDepth
double m_rayMaxDepth
Max depth of the ray before stopping.
Definition: MaterialScan.h:362
Belle2::MaterialScan2D::ScanParams::nU
int nU
Number of rays along u coordinate.
Definition: MaterialScan.h:90
Belle2::MaterialScan2D::m_regions
std::map< std::string, std::unique_ptr< TH2D > > m_regions
Map holding pointers to all created histograms.
Definition: MaterialScan.h:161
Belle2::MaterialScanModule::m_rayOrigin
std::vector< double > m_rayOrigin
Origin of the ray if a ray scan is performed
Definition: MaterialScan.h:348
Belle2::MaterialScanModule::m_rayDirection
boost::optional< std::vector< double > > m_rayDirection
Direction of the ray, cannot be set at the same time as Theta and Phi.
Definition: MaterialScan.h:352
Belle2::MaterialScanModule::m_rayCount
unsigned int m_rayCount
Number of rays to shoot (if opening angle is >0)
Definition: MaterialScan.h:364
REG_MODULE
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:652
Belle2::MaterialScan2D::ScanParams::maxV
double maxV
Maximum v value to scan.
Definition: MaterialScan.h:100
Belle2::MaterialScanRay::getHistogram
TH1D * getHistogram(const std::string &name)
get histogram for a given name, create if needed.
Definition: MaterialScan.cc:256
Belle2::Module::event
virtual void event()
This method is the core of the module.
Definition: Module.h:159
Belle2::MaterialScanModule::beginRun
void beginRun() override
Do the actual scanning.
Definition: MaterialScan.cc:480
Belle2::MaterialScan2D::ScanParams::nV
int nV
Number of rays along v coordinate.
Definition: MaterialScan.h:92
Belle2::MaterialScanModule::m_spherical
MaterialScan2D::ScanParams m_spherical
Scan parameters for the spherical scan.
Definition: MaterialScan.h:340
Belle2::MaterialScanRay::m_scanDepth
double m_scanDepth
The first ray does not record any material but just checks for the maximum useful depth to not get a ...
Definition: MaterialScan.h:295
Belle2::MaterialScanRay
MaterialScan implementation to shoot one ray along a defined direction and record the Material as a f...
Definition: MaterialScan.h:242
Belle2::MaterialScan2D::ScanParams::splitByMaterials
bool splitByMaterials
If true, split output by Materials (otherwise by region)
Definition: MaterialScan.h:106
Belle2::MaterialScanPlanar::m_origin
G4ThreeVector m_origin
Origin of the scan plane.
Definition: MaterialScan.h:225
Belle2::MaterialScanSpherical::m_doCosTheta
bool m_doCosTheta
Flag to indicate if polar-angular sampling is uniform in cos(theta) rather than theta.
Definition: MaterialScan.h:195
Belle2::MaterialScanSpherical
Specific implementation of MaterialScan to do Spherical scanning.
Definition: MaterialScan.h:167
Belle2::MaterialScan2D::m_stepV
double m_stepV
Stepsize for the parameter v.
Definition: MaterialScan.h:157
Belle2::MaterialScanModule::m_raySampleDepth
double m_raySampleDepth
Sample depth of the ray: create one bin every x cm.
Definition: MaterialScan.h:360
Belle2::MaterialScanSpherical::getRay
void getRay(G4ThreeVector &origin, G4ThreeVector &direction) override
Create a ray with the current parameter values according to a spherical distribution.
Definition: MaterialScan.cc:196
Belle2::MaterialScanBase::m_axisLabel
std::string m_axisLabel
Labels for the coordinate axes.
Definition: MaterialScan.h:67
Belle2::MaterialScanRay::m_curRay
int m_curRay
Current Ray number: 0 = scan for maximum depth, 1..N = record materials.
Definition: MaterialScan.h:299
Belle2::MaterialScanRay::m_curDepth
double m_curDepth
Current depth of the current ray.
Definition: MaterialScan.h:289
Belle2::MaterialScan2D::m_stepU
double m_stepU
Stepsize for the parameter u.
Definition: MaterialScan.h:153
Belle2::MaterialScanModule::m_sphericalOrigin
std::vector< double > m_sphericalOrigin
Origin for spherical scan.
Definition: MaterialScan.h:346
Belle2::MaterialScanRay::m_maxDepth
double m_maxDepth
Maximum depth for each ray after which it will be stopped.
Definition: MaterialScan.h:287
Belle2::MaterialScanPlanar::m_dirV
G4ThreeVector m_dirV
v direction of the scan plane
Definition: MaterialScan.h:229
Belle2::MaterialScanRay::m_count
int m_count
Amount of rays to shoot.
Definition: MaterialScan.h:297
Belle2::MaterialScanModule::m_rayPhi
double m_rayPhi
Phi direction of the ray if custom direction is not set.
Definition: MaterialScan.h:356
Belle2::MaterialScanBase
Base class for Material Scans.
Definition: MaterialScan.h:36
Belle2::MaterialScanSpherical::m_origin
G4ThreeVector m_origin
Origin for the spherical scan.
Definition: MaterialScan.h:192
Belle2::MaterialScanModule::m_customPlane
std::vector< double > m_customPlane
Custom plane definition if m_planName is "custom".
Definition: MaterialScan.h:344
Belle2::MaterialScan2D::createNext
bool createNext(G4ThreeVector &origin, G4ThreeVector &direction) override
Get the origin and direction for the next scan particle.
Definition: MaterialScan.cc:99
Belle2::MaterialScanModule::m_rayOpening
double m_rayOpening
Opening angle of the ray.
Definition: MaterialScan.h:358
Belle2::MaterialScan2D::UserSteppingAction
void UserSteppingAction(const G4Step *step) override
Record the material budget for each step of the particles.
Definition: MaterialScan.cc:146
Belle2::MaterialScanModule::m_rootFile
TFile * m_rootFile
Pointer to the ROOT file for the histograms.
Definition: MaterialScan.h:334
Belle2::MaterialScan2D::ScanParams::minU
double minU
Minimum u value to scan.
Definition: MaterialScan.h:94
Belle2::MaterialScanModule::m_planeName
std::string m_planeName
Name of the plane to use for scanning.
Definition: MaterialScan.h:338
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::MaterialScanPlanar::m_dirU
G4ThreeVector m_dirU
u direction of the scan plane
Definition: MaterialScan.h:227
Belle2::MaterialScanModule::m_rayIgnoredMaterials
std::vector< std::string > m_rayIgnoredMaterials
Materials ignored when ray scanning.
Definition: MaterialScan.h:350
Belle2::MaterialScanModule::m_doSpherical
bool m_doSpherical
Wether or not to do a spherical scan.
Definition: MaterialScan.h:366
Belle2::MaterialScanPlanar::getRay
void getRay(G4ThreeVector &origin, G4ThreeVector &direction) override
Create a ray with the current parameter values according to a planar distribution.
Definition: MaterialScan.cc:210
Belle2::MaterialScanBase::m_name
std::string m_name
Name of the scan, will be prefixed to all histogram names.
Definition: MaterialScan.h:65
LogVar
Class to store variables with their name which were sent to the logging service.
Definition: LogVariableStream.h:24
Belle2::MaterialScanPlanar::m_dirW
G4ThreeVector m_dirW
direction perpendicluar to u and v
Definition: MaterialScan.h:231
Belle2::MaterialScan2D::m_curU
double m_curU
Current value of the parametetr u.
Definition: MaterialScan.h:151
Belle2::MaterialScan2D::ScanParams::maxDepth
double maxDepth
Maximum depth of the scan.
Definition: MaterialScan.h:102
Belle2::MaterialScanRay::m_ignoredMaterials
std::set< std::string > m_ignoredMaterials
Materials ignored when scanning.
Definition: MaterialScan.h:275
Belle2::MaterialScanBase::checkStep
bool checkStep(const G4Step *step)
check for stuck tracks by looking at the step length
Definition: MaterialScan.cc:46
Belle2::MaterialScanModule::m_doCosTheta
bool m_doCosTheta
Perform the spherical scan uniform in cos(theta) instead of theta.
Definition: MaterialScan.h:370
Belle2::Unit::deg
static const double deg
degree to radians
Definition: Unit.h:119
Belle2::MaterialScan2D::m_curV
double m_curV
Current value of the parametetr v.
Definition: MaterialScan.h:155
Belle2::MaterialScanRay::m_sampleDepth
double m_sampleDepth
The ray length after which to sample.
Definition: MaterialScan.h:285
Belle2::MaterialScan2D::m_curDepth
double m_curDepth
Tracklength of the current Ray.
Definition: MaterialScan.h:159
Belle2::MaterialScan2D::ScanParams::minV
double minV
Minimum v value to scan.
Definition: MaterialScan.h:98
Belle2::MaterialScanPlanar
Specific implementaion of MaterialScan to scan parallel to a given plane.
Definition: MaterialScan.h:205
Belle2::MaterialScanRay::m_origin
G4ThreeVector m_origin
Origin of the scan.
Definition: MaterialScan.h:279
Belle2::MaterialScanModule::initialize
void initialize() override
Initialize the output file and check the parameters.
Definition: MaterialScan.cc:441
Belle2::MaterialScan2D::ScanParams
Helper struct to Store Parameters of a Scan.
Definition: MaterialScan.h:86
Belle2::Unit::mm
static const double mm
[millimeters]
Definition: Unit.h:80
Belle2::Utils::getClock
double getClock()
Return current value of the real-time clock.
Definition: Utils.cc:58
Belle2::MaterialScanRay::UserSteppingAction
void UserSteppingAction(const G4Step *step) override
Record the material budget for each step of the particles.
Definition: MaterialScan.cc:284
Belle2::MaterialScanRay::fillValue
void fillValue(const std::string &name, double value, double steplength)
Fill the recorded material budget into the corresponding histogram.
Definition: MaterialScan.cc:268
Belle2::MaterialScanRay::createNext
bool createNext(G4ThreeVector &origin, G4ThreeVector &direction) override
Implement shooting along the ray.
Definition: MaterialScan.cc:217
Belle2::MaterialScanModule::m_doPlanar
bool m_doPlanar
Wether or not to do a planar scan.
Definition: MaterialScan.h:368
Belle2::MaterialScanModule::getAxis
G4ThreeVector getAxis(char name)
Return a vector along the axis with the given name.
Definition: MaterialScan.cc:579
Belle2::MaterialScanModule::m_rayTheta
double m_rayTheta
Theta direction of the ray if custom direction is not set.
Definition: MaterialScan.h:354
Belle2::MaterialScanRay::m_splitByMaterials
bool m_splitByMaterials
If true Split by materials instead of regions.
Definition: MaterialScan.h:301
Belle2::MaterialScanModule::m_planar
MaterialScan2D::ScanParams m_planar
Scan parameters for the planar scan.
Definition: MaterialScan.h:342
Belle2::MaterialScanBase::m_rootFile
TFile * m_rootFile
Pointer to the root file for the histograms.
Definition: MaterialScan.h:63
Belle2::MaterialScanRay::m_dir
G4ThreeVector m_dir
Direction of the ray.
Definition: MaterialScan.h:281
Belle2::MaterialScan2D::ScanParams::ignoredMaterials
std::vector< std::string > ignoredMaterials
Names of ignored Materials.
Definition: MaterialScan.h:104
Belle2::MaterialScan2D::ScanParams::maxU
double maxU
Maximum u value to scan.
Definition: MaterialScan.h:96
Belle2::MaterialScan2D::m_params
ScanParams m_params
Parameters for the scan.
Definition: MaterialScan.h:149
Belle2::MaterialScanModule::m_filename
std::string m_filename
Filename for the ROOT output.
Definition: MaterialScan.h:336