Belle II Software  release-05-02-19
Geant4MaterialInterface.cc
1 #include <framework/logging/Logger.h>
2 #include <tracking/modules/genfitUtilities/Geant4MaterialInterface.h>
3 #include <geometry/GeometryManager.h>
4 
5 #include "genfit/Exception.h"
6 #include "genfit/RKTrackRep.h"
7 
8 #include <assert.h>
9 #include <math.h>
10 
11 #include "G4ThreeVector.hh"
12 #include "G4Navigator.hh"
13 #include "G4VPhysicalVolume.hh"
14 #include "G4LogicalVolume.hh"
15 #include "G4Material.hh"
16 #include "G4TouchableHistory.hh"
17 
18 
19 #include <G4VExceptionHandler.hh>
20 #include <G4StateManager.hh>
21 
22 
23 static const bool debug = false;
24 
25 using namespace Belle2;
26 
27 namespace Belle2 {
38  class Geant4MaterialInterfaceExceptioHandler : public G4VExceptionHandler {
39  public:
43  virtual ~Geant4MaterialInterfaceExceptioHandler() = default;
44 
48  virtual bool Notify(const char* origin, const char* code, G4ExceptionSeverity serv, const char* description)
49  {
50  B2WARNING("Geant4 exception during material lookup -- origin: "
51  << origin << "\n code:"
52  << code << "\n description:"
53  << description);
54 
55  if (serv == EventMustBeAborted || serv == RunMustBeAborted) {
56  m_inFailureState = true;
57  }
58 
59  if (serv == FatalException || serv == FatalErrorInArgument) {
60  // on fatal exceptions, instruct Geant4 to create core dump
61  // and crash
62  return true;
63  }
64 
65  // returning false will continue the program execution
66  // G4ExceptionSeverity = JustWarning will be covered by this, too
67  return false;
68  }
69 
73  bool isInFailureState() const
74  {
75  return m_inFailureState;
76  }
77 
83  {
84  m_inFailureState = false;
85  }
86 
87  private:
91  bool m_inFailureState = false;
92  };
93 
101  public:
102  G4SafeNavigator() = default;
103  ~G4SafeNavigator() = default;
104 
108  G4VPhysicalVolume* GetWorldVolume() const { return nav_.GetWorldVolume(); }
109 
113  void SetWorldVolume(G4VPhysicalVolume* pWorld)
114  {
115  nav_.SetWorldVolume(pWorld);
116  worldsolid_ = pWorld->GetLogicalVolume()->GetSolid();
117  }
118 
123  G4VPhysicalVolume* LocateGlobalPointAndSetup(const G4ThreeVector& point,
124  const G4ThreeVector* direction = 0,
125  const G4bool pRelativeSearch = true,
126  const G4bool ignoreDirection = true);
127 
131  G4double CheckNextStep(const G4ThreeVector& pGlobalPoint,
132  const G4ThreeVector& pDirection,
133  const G4double pCurrentProposedStepLength,
134  G4double& pNewSafety);
135 
140  G4VPhysicalVolume* ResetHierarchyAndLocate(const G4ThreeVector& point,
141  const G4ThreeVector& direction,
142  const G4TouchableHistory& h);
143 
148 
152  G4TouchableHistory* CreateTouchableHistory() const
153  {
154  return nav_.CreateTouchableHistory();
155  }
156 
157  private:
158 
164  {
165  otherHandler = G4StateManager::GetStateManager()->GetExceptionHandler();
167  G4StateManager::GetStateManager()->SetExceptionHandler(&exceptionHandler);
168  }
169 
175  {
176  G4StateManager::GetStateManager()->SetExceptionHandler(otherHandler);
177 
178  // was the a problem in the last usage ?
180  genfit::Exception exc("Geant4MaterialInterface::findNextBoundary ==> Geant4 exception during geometry navigation", __LINE__,
181  __FILE__);
182  exc.setFatal();
183  throw exc;
184  }
185  }
186 
188  G4ThreeVector lastpoint_;
190  G4VPhysicalVolume* lastvolume_{0};
192  G4Navigator nav_;
194  const G4VSolid* worldsolid_ {0};
196  G4VExceptionHandler* otherHandler = nullptr;
199  };
201 }
202 
204 {
205  nav_.SetGeometricallyLimitedStep();
206 }
207 
208 G4VPhysicalVolume* G4SafeNavigator::LocateGlobalPointAndSetup(const G4ThreeVector& point,
209  const G4ThreeVector* direction,
210  const G4bool pRelativeSearch,
211  const G4bool ignoreDirection)
212 {
213  if (point == lastpoint_ && lastvolume_) {
214  return lastvolume_;
215  }
216  //B2INFO("### init: " << point);
217 
219  G4VPhysicalVolume* volume = nav_.LocateGlobalPointAndSetup(point, direction, pRelativeSearch, ignoreDirection);
221 
222  if (!volume) {
223  volume = nav_.GetWorldVolume();
224  }
225  // remember last point to speed up setup if possible
226  lastpoint_ = point;
227  lastvolume_ = volume;
228  return volume;
229 }
230 
231 G4VPhysicalVolume* G4SafeNavigator::ResetHierarchyAndLocate(const G4ThreeVector& point,
232  const G4ThreeVector& direction,
233  const G4TouchableHistory& h)
234 {
235  if (point == lastpoint_ && lastvolume_) {
236  return lastvolume_;
237  }
238  //B2INFO("### reset: " << point);
240  G4VPhysicalVolume* volume = nav_.ResetHierarchyAndLocate(point, direction, h);
242 
243  if (!volume) {
244  volume = nav_.GetWorldVolume();
245  }
246  // remember last point to speed up setup if possible
247  lastpoint_ = point;
248  lastvolume_ = volume;
249  return volume;
250 }
251 
252 G4double G4SafeNavigator::CheckNextStep(const G4ThreeVector& point,
253  const G4ThreeVector& direction,
254  const G4double pCurrentProposedStepLength,
255  G4double& pNewSafety)
256 {
257  //make sure we're inside the world volume
258  if (worldsolid_->Inside(point) == kOutside) {
259  pNewSafety = worldsolid_->DistanceToIn(point);
260  return worldsolid_->DistanceToIn(point, direction);
261  }
262 
264  const auto distance = nav_.CheckNextStep(point, direction, pCurrentProposedStepLength, pNewSafety);
266 
267  return distance;
268 }
269 
270 
271 Geant4MaterialInterface::Geant4MaterialInterface()
272  : nav_(new G4SafeNavigator()), currentVolume_(0)
273 {
274  G4VPhysicalVolume* world = geometry::GeometryManager::getInstance().getTopVolume();
275  nav_->SetWorldVolume(world);
276 }
277 
278 Geant4MaterialInterface::~Geant4MaterialInterface()
279 {
280 }
281 
282 
283 bool
284 Geant4MaterialInterface::initTrack(double posX, double posY, double posZ,
285  double dirX, double dirY, double dirZ)
286 {
287  G4ThreeVector pos(posX * CLHEP::cm, posY * CLHEP::cm, posZ * CLHEP::cm);
288  G4ThreeVector dir(dirX, dirY, dirZ);
289 
290  if (m_takingFullStep) {
291  m_takingFullStep = false;
292  nav_->SetGeometricallyLimitedStep();
293  }
294 
295  const G4VPhysicalVolume* newVolume = nav_->LocateGlobalPointAndSetup(pos, &dir);
296  bool volChanged = newVolume != currentVolume_;
297  currentVolume_ = newVolume;
298 
299  return volChanged;
300 }
301 
302 
305 {
306  assert(currentVolume_);
307 
308  const G4Material* mat = currentVolume_->GetLogicalVolume()->GetMaterial();
309 
310  double density, Z, A, radiationLength, mEE;
311  if (mat->GetNumberOfElements() == 1) {
312  Z = mat->GetZ();
313  A = mat->GetA();
314  } else {
315  // Calculate weight-averaged A, Z
316  A = Z = 0;
317  for (unsigned i = 0; i < mat->GetNumberOfElements(); ++i) {
318  const G4Element* element = (*mat->GetElementVector())[i];
319  Z += element->GetZ() * mat->GetFractionVector()[i];
320  A += element->GetA() * mat->GetFractionVector()[i];
321  }
322  }
323 
324  density = mat->GetDensity() / CLHEP::g * CLHEP::cm3;
325  // Z has correct units
326  A *= CLHEP::mole / CLHEP::g;
327  radiationLength = mat->GetRadlen() / CLHEP::cm;
328  mEE = mat->GetIonisation()->GetMeanExcitationEnergy() / CLHEP::eV;
329  return genfit::Material(density, Z, A, radiationLength, mEE);
330 }
331 
332 
333 double
335  const genfit::M1x7& stateOrig,
336  double sMax, // signed
337  bool varField)
338 {
339  // This assumes that sMax is small enough to take only a single RK
340  // step. This restriction comes about because RKPropagate only
341  // takes one step.
342  const double delta(1.E-2); // cm, distance limit beneath which straight-line steps are taken.
343  const double epsilon(1.E-1); // cm, allowed upper bound on arch deviation from straight line
344 
345  genfit::M1x3 SA;
346  genfit::M1x7 state7, oldState7;
347  oldState7 = stateOrig;
348 
349  int stepSign(sMax < 0 ? -1 : 1);
350 
351  G4ThreeVector pointOld(stateOrig[0] * CLHEP::cm,
352  stateOrig[1] * CLHEP::cm,
353  stateOrig[2] * CLHEP::cm);
354  G4ThreeVector dirOld(stepSign * stateOrig[3],
355  stepSign * stateOrig[4],
356  stepSign * stateOrig[5]);
357 
358  double s = 0; // trajectory length to boundary
359 
360  const unsigned maxIt = 300;
361  unsigned it = 0;
362 
363  // Initialize the geometry to the current location (set by caller).
364  double safety;
365 
366  m_takingFullStep = false;
367  double slDist = nav_->CheckNextStep(pointOld, dirOld, fabs(sMax) * CLHEP::cm, safety);
368  if (slDist == kInfinity) {
369  slDist = fabs(sMax);
370  m_takingFullStep = true;
371  } else {
372  slDist /= CLHEP::cm;
373  }
374  safety /= CLHEP::cm;
375 
376  // No boundary in sight?
377  if (safety > fabs(sMax)) {
378  if (debug)
379  std::cout << " next boundary is farther away than sMax \n";
380  return stepSign * safety; // sMax
381  }
382 
383  // Are we at the boundary?
384  if (slDist < delta) {
385  if (debug)
386  std::cout << " very close to the boundary -> return @ it " << it
387  << " stepSign*slDist = "
388  << stepSign << "*" << slDist << "\n";
389  return stepSign * slDist;
390  }
391  double step = slDist;
392 
393  while (1) {
394  if (++it > maxIt) {
395  genfit::Exception exc("Geant4MaterialInterface::findNextBoundary ==> maximum number of iterations exceeded", __LINE__, __FILE__);
396  exc.setFatal();
397  throw exc;
398  }
399 
400  if (step < delta)
401  return stepSign * (s + step);
402 
403  // We have to find whether there's any boundary on our path.
404 
405  // Follow curved arch, then see if we may have missed a boundary.
406  // Always propagate complete way from original start to avoid
407  // inconsistent extrapolations. This is always a single RK step.
408  state7 = stateOrig;
409  rep->RKPropagate(state7, NULL, SA, stepSign * (s + step), varField);
410 
411  G4ThreeVector pos(state7[0] * CLHEP::cm, state7[1] * CLHEP::cm, state7[2] * CLHEP::cm);
412  G4ThreeVector dir(stepSign * state7[3], stepSign * state7[4], stepSign * state7[5]);
413 
414  // Straight line distance between extrapolation finish and
415  // the end of the previously determined safe segment.
416  double dist2 = (pow(state7[0] - oldState7[0], 2)
417  + pow(state7[1] - oldState7[1], 2)
418  + pow(state7[2] - oldState7[2], 2));
419 
420  // If we moved less than safety, the volume cannot possibly have
421  // changed, so we skip further checks.
422  if (dist2 > safety * safety) {
423 
424  // Do we need to try again with a shorter step? There are two
425  // possible reasons:
426  //
427  // 1. Too much curvature?
428 
429  // Maximal lateral deviation² of the curved path from the
430  // straight line connecting beginning and end.
431  double maxDeviation2 = 0.25 * (step * step - dist2);
432  if (maxDeviation2 > epsilon * epsilon) {
433  // Need to take a shorter step to reliably estimate material,
434  // but only if we didn't move by safety.
435 
436  // Take a shorter step, but never shorter than safety.
437  step = safety + 0.5 * (step - safety);
438 
439  continue;
440  }
441 
442  // 2. Volume changed?
443  //
444  // Where are we after the step?
445 
446  if (m_takingFullStep) {
447  m_takingFullStep = false;
448  nav_->SetGeometricallyLimitedStep();
449  }
450 
451  std::unique_ptr<G4TouchableHistory> hist(nav_->CreateTouchableHistory());
452  G4VPhysicalVolume* newVolume = nav_->LocateGlobalPointAndSetup(pos, &dir);
453 
454  if (newVolume != currentVolume_) {
455 
456  // Volume changed during the extrapolation.
457 
458  // Extrapolation may not take the exact step length we asked
459  // for, so it can happen that a requested step < safety takes
460  // us across the boundary. This is then the best estimate we
461  // can get of the distance to the boundary with the stepper.
462  if (step <= safety)
463  return stepSign * (s + step);
464 
465  // Move back to last good point, but looking in the actual
466  // direction of the step.
467  G4ThreeVector dirCloser(pos - pointOld);
468  dirCloser.setMag(1.);
469  nav_->ResetHierarchyAndLocate(pointOld, dirCloser, *hist);
470 
471  // Look along the secant of the actual trajectory instead of
472  // the original direction. There should be a crossing within
473  // distance step.
474  double secantDist = nav_->CheckNextStep(pointOld, dirCloser,
475  step * CLHEP::cm, safety) / CLHEP::cm;
476  safety /= CLHEP::cm;
477  if (secantDist >= step) {
478  // Cannot be. Just take a shorter step, and hope that this
479  // works.
480  slDist = secantDist;
481  step = std::max(0.9 * step, safety);
482  } else {
483  slDist = step = std::max(secantDist, safety);
484  }
485 
486  // Are we at the boundary?
487  if (slDist < delta) {
488  if (debug)
489  std::cout << " very close to the boundary -> return @ it " << it
490  << " stepSign*(s + slDist) = "
491  << stepSign << "*(" << s + slDist << ")\n";
492  return stepSign * (s + slDist);
493  }
494 
495  continue;
496  }
497  }
498 
499  // We're in the new place, the step was safe, advance.
500  s += step;
501 
502  oldState7 = state7;
503  pointOld = pos;
504  if (m_takingFullStep) {
505  m_takingFullStep = false;
506  // inform the navigator that the full geometrical step was taken. This is required for
507  // some Geant4 volume enter/exit optimizations to work.
508  nav_->SetGeometricallyLimitedStep();
509  }
510  nav_->LocateGlobalPointAndSetup(pos, &dir);
511  slDist = nav_->CheckNextStep(pos, dir,
512  (fabs(sMax) - s) * CLHEP::cm, safety);
513  if (slDist == kInfinity) {
514  m_takingFullStep = true;
515  slDist = fabs(sMax) - s;
516  } else {
517  slDist /= CLHEP::cm;
518  }
519  safety /= CLHEP::cm;
520  step = slDist;
521 
522  // No boundary in sight?
523  if (s + safety > fabs(sMax)) {
524  if (debug)
525  std::cout << " next boundary is farther away than sMax \n";
526  return stepSign * (s + safety); // sMax
527  }
528 
529  // Are we at the boundary?
530  if (slDist < delta) {
531  if (debug)
532  std::cout << " very close to the boundary -> return @ it " << it
533  << " stepSign*(s + slDist) = "
534  << stepSign << "*(" << s + slDist << ")\n";
535  return stepSign * (s + slDist);
536  }
537  }
538 }
Belle2::G4SafeNavigator::uninstallAndCheckOurExceptionHandler
void uninstallAndCheckOurExceptionHandler()
Reinstate the previously used exception handler and check whether a critical exception was recorded b...
Definition: Geant4MaterialInterface.cc:174
genfit::Exception
Exception class for error handling in GENFIT (provides storage for diagnostic information)
Definition: Exception.h:48
genfit::Exception::setFatal
void setFatal(bool b=true)
Set fatal flag.
Definition: Exception.h:61
Belle2::G4SafeNavigator::worldsolid_
const G4VSolid * worldsolid_
The topmost solid of the G4 world.
Definition: Geant4MaterialInterface.cc:194
Belle2::Geant4MaterialInterfaceExceptioHandler::Notify
virtual bool Notify(const char *origin, const char *code, G4ExceptionSeverity serv, const char *description)
G4VExceptionHandler method called when an exception is raised.
Definition: Geant4MaterialInterface.cc:48
Belle2::Geant4MaterialInterfaceExceptioHandler
This class implements a custom exception handler for Geant4 which is used to record whether a critica...
Definition: Geant4MaterialInterface.cc:38
genfit::RKTrackRep::RKPropagate
virtual double RKPropagate(M1x7 &state7, M7x7 *jacobian, M1x3 &SA, double S, bool varField=true, bool calcOnlyLastRowOfJ=false) const
The actual Runge Kutta propagation.
Definition: RKTrackRep.cc:1272
Belle2::G4SafeNavigator::exceptionHandler
Geant4MaterialInterfaceExceptioHandler exceptionHandler
Custom exception handler to handle stuck tracks properly (and abort)
Definition: Geant4MaterialInterface.cc:198
Belle2::Geant4MaterialInterface::nav_
std::unique_ptr< class G4SafeNavigator > nav_
holds a object of G4SafeNavigator, which is located in Geant4MaterialInterface.cc
Definition: Geant4MaterialInterface.h:59
Belle2::geometry::GeometryManager::getTopVolume
G4VPhysicalVolume * getTopVolume()
Return a pointer to the top volume.
Definition: GeometryManager.h:59
Belle2::G4SafeNavigator::installOurExceptionHandler
void installOurExceptionHandler()
Install our specific exception handler and cache the one which was set before.
Definition: Geant4MaterialInterface.cc:163
Belle2::Geant4MaterialInterface::m_takingFullStep
bool m_takingFullStep
stores whether to call SetGeometricallyLimitedStep() because the full step length was taken.
Definition: Geant4MaterialInterface.h:67
Belle2::geometry::GeometryManager::getInstance
static GeometryManager & getInstance()
Return a reference to the instance.
Definition: GeometryManager.cc:98
Belle2::Geant4MaterialInterfaceExceptioHandler::resetFailureState
void resetFailureState()
Reset the recorded failure state to be ready for the next calls to Geant4.
Definition: Geant4MaterialInterface.cc:82
Belle2::Geant4MaterialInterfaceExceptioHandler::~Geant4MaterialInterfaceExceptioHandler
virtual ~Geant4MaterialInterfaceExceptioHandler()=default
virtual destructor for proper resource de-allocation
Belle2::G4SafeNavigator::LocateGlobalPointAndSetup
G4VPhysicalVolume * LocateGlobalPointAndSetup(const G4ThreeVector &point, const G4ThreeVector *direction=0, const G4bool pRelativeSearch=true, const G4bool ignoreDirection=true)
Use Geant4's LocateGlobalPointAndSetup to get a G4VPhysicalVolume or use cached values from previous ...
Definition: Geant4MaterialInterface.cc:208
Belle2::G4SafeNavigator::CheckNextStep
G4double CheckNextStep(const G4ThreeVector &pGlobalPoint, const G4ThreeVector &pDirection, const G4double pCurrentProposedStepLength, G4double &pNewSafety)
Check if within world volume and call Geant4's CheckNextStep.
Definition: Geant4MaterialInterface.cc:252
Belle2::G4SafeNavigator
Guards against leaving the physical volume.
Definition: Geant4MaterialInterface.cc:100
genfit::RKTrackRep
AbsTrackRep with 5D track parameterization in plane coordinates: (q/p, u', v', u, v)
Definition: RKTrackRep.h:72
Belle2::Geant4MaterialInterface::currentVolume_
const class G4VPhysicalVolume * currentVolume_
the volume the extraoplation is currenly located in
Definition: Geant4MaterialInterface.h:62
genfit::RKMatrix< 1, 7 >
Belle2::Geant4MaterialInterface::initTrack
bool initTrack(double posX, double posY, double posZ, double dirX, double dirY, double dirZ) override
Initialize the navigator at given position and with given direction.
Definition: Geant4MaterialInterface.cc:284
Belle2::G4SafeNavigator::GetWorldVolume
G4VPhysicalVolume * GetWorldVolume() const
Returns the Geant4 world volume.
Definition: Geant4MaterialInterface.cc:108
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::Geant4MaterialInterfaceExceptioHandler::isInFailureState
bool isInFailureState() const
Returns true if a problematic exception was encountered.
Definition: Geant4MaterialInterface.cc:73
Belle2::G4SafeNavigator::lastvolume_
G4VPhysicalVolume * lastvolume_
the last volume which has been queried
Definition: Geant4MaterialInterface.cc:190
Belle2::G4SafeNavigator::otherHandler
G4VExceptionHandler * otherHandler
Stores the pointer to exception handler which this class temporarily replaces for most calls.
Definition: Geant4MaterialInterface.cc:196
Belle2::Geant4MaterialInterfaceExceptioHandler::m_inFailureState
bool m_inFailureState
Stores whether a problematic exception occured.
Definition: Geant4MaterialInterface.cc:91
Belle2::G4SafeNavigator::nav_
G4Navigator nav_
Geant4's navigator which calls are forwarded to.
Definition: Geant4MaterialInterface.cc:192
Belle2::G4SafeNavigator::SetWorldVolume
void SetWorldVolume(G4VPhysicalVolume *pWorld)
Sets the Geant4 world volume.
Definition: Geant4MaterialInterface.cc:113
Belle2::G4SafeNavigator::ResetHierarchyAndLocate
G4VPhysicalVolume * ResetHierarchyAndLocate(const G4ThreeVector &point, const G4ThreeVector &direction, const G4TouchableHistory &h)
Call Geant4's ResetHierarchyAndLocate to get a G4VPhysicalVolume or use cached values from previous c...
Definition: Geant4MaterialInterface.cc:231
Belle2::G4SafeNavigator::lastpoint_
G4ThreeVector lastpoint_
the last point which has been queried with G4
Definition: Geant4MaterialInterface.cc:188
Belle2::G4SafeNavigator::SetGeometricallyLimitedStep
void SetGeometricallyLimitedStep()
Calls Geant4's SetGeometricallyLimitedStep.
Definition: Geant4MaterialInterface.cc:203
Belle2::Geant4MaterialInterface::getMaterialParameters
genfit::Material getMaterialParameters() override
Get material parameters in current material.
Definition: Geant4MaterialInterface.cc:304
Belle2::Geant4MaterialInterface::findNextBoundary
double findNextBoundary(const genfit::RKTrackRep *rep, const genfit::M1x7 &state7, double sMax, bool varField=true) override
Make a step (following the curvature) until step length sMax or the next boundary is reached.
Definition: Geant4MaterialInterface.cc:334
Belle2::G4SafeNavigator::CreateTouchableHistory
G4TouchableHistory * CreateTouchableHistory() const
Call Geant4's CreateTouchableHistory.
Definition: Geant4MaterialInterface.cc:152
genfit::Material
Definition: Material.h:10