Project
Loading...
Searching...
No Matches
VecGeomG4PropagatingNavigator.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
13
14#include "G4TouchableHistory.hh"
15#include "G4VPhysicalVolume.hh"
16
17#include <VecGeom/base/Transformation3D.h>
18#include <VecGeom/management/GeoManager.h>
19#include <VecGeom/navigation/GlobalLocator.h>
20#include <VecGeom/navigation/VNavigator.h>
21#include <VecGeom/navigation/VSafetyEstimator.h>
22#include <VecGeom/volumes/LogicalVolume.h>
23#include <VecGeom/volumes/PlacedVolume.h>
24
25#include <fairlogger/Logger.h>
26
27#include <cmath>
28
29namespace
30{
33const double kNudge = 1.e-3;
34} // namespace
35
36namespace o2::simsetup
37{
38
40 : VecGeomG4NavigatorBase(map), mZeroSafety(zeroSafety)
41{
42 mEmptyState.Clear();
43}
44
46{
47 LOG(info) << "VecGeom navigation: " << mNudgedSteps << " stalled steps nudged forward, " << mGlobalRelocates
48 << " relocations restarted from the world";
49}
50
51G4double VecGeomG4PropagatingNavigator::ComputeStep(const G4ThreeVector& globalPoint, const G4ThreeVector& direction,
52 const G4double proposedStepLength, G4double& newSafety)
53{
54 newSafety = 0.;
55 mLastDirection = direction;
56 mHaveNextState = false;
57
58 auto const* top = mCurState.Top();
59 if (top == nullptr) { // the track is outside the world
60 mWouldEnter = mWouldExit = false;
61 return kInfinity;
62 }
63 auto const* navigator = top->GetLogicalVolume()->GetNavigator();
64
65 double limit = proposedStepLength * kG4ToVG;
66 if (!(limit < vecgeom::kInfLength)) {
67 limit = vecgeom::kInfLength;
68 }
69
70 // VecGeom's own combined entry point, rather than a step followed by a relocation of our own: it
71 // is the one that knows how to descend through an assembly, whose placed volume can never be the
72 // answer because it has no DistanceToOut.
73 // The adopted state marks the volume the crossing left. As in Geant4, it is blocked in the first
74 // step after the exit only, and only while the direction points away from it; a track turning
75 // back into it must see its boundary.
76 const bool block = mExitBlockPending && globalPoint.diff2(mLocatedPoint) < 1.e-20 &&
77 directionLeaves(mPrevState, toVG(globalPoint), toDir(direction));
78 mExitBlockPending = false;
79 if (!block) {
80 mCurState.SetLastExited(mEmptyState.GetLastExitedState());
81 }
82
83 double vgSafety = 0.;
84 const double vgStep = navigator->ComputeStepAndSafetyAndPropagatedState(
85 toVG(globalPoint), toDir(direction), limit, mCurState, mNextState, !mOnBoundary && !mZeroSafety, vgSafety);
86 mOnBoundary = false;
87 newSafety = (vgSafety > 0. && !mZeroSafety) ? vgSafety * kVGToG4 : 0.;
88
89 G4double step = vgStep * kVGToG4;
90 if (mNextState.IsOnBoundary()) {
91 // Entering a daughter deepens the state, possibly by more than one level when an assembly
92 // stands in between; leaving the current volume does not.
93 mWouldEnter = mNextState.GetCurrentLevel() > mCurState.GetCurrentLevel();
94 mWouldExit = !mWouldEnter;
95 mNextPoint = globalPoint + step * direction;
96 mHaveNextState = true;
97 } else {
98 mWouldEnter = mWouldExit = false;
99 step = kInfinity;
100 }
101
102 if (vgStep < 0.) {
103 // A negative distance means the state and the point disagree. Nudge forward and relocate from
104 // the world on the next call rather than propagating the inconsistency.
105 mForceReInit = true;
106 mHaveNextState = false;
107 ++mNudgedSteps;
108 mZeroSteps = 0;
109 return kNudge;
110 }
111 if (step < 1.e-10) {
112 if (++mZeroSteps > 4) {
113 mForceReInit = true;
114 mHaveNextState = false;
115 ++mNudgedSteps;
116 return kNudge;
117 }
118 } else {
119 mForceReInit = false;
120 mZeroSteps = 0;
121 }
122 return step;
123}
124
125G4VPhysicalVolume* VecGeomG4PropagatingNavigator::ResetHierarchyAndLocate(const G4ThreeVector&, const G4ThreeVector&,
126 const G4TouchableHistory& history)
127{
128 // Geant4 hands back a touchable it saved earlier, e.g. when resuming a track whose secondaries
129 // were followed first. The VecGeom state is rebuilt from it.
130 fEnteredDaughter = false;
131 fExitedMother = false;
132 mWouldEnter = false;
133 mWouldExit = false;
134 mOnBoundary = false;
135 mHaveNextState = false;
136 fHistory = *history.GetHistory();
137 if (!stateFromHistory(mCurState) && fHistory.GetVolume(0) != nullptr) {
138 LOG(fatal) << "Geant4 handed back a touchable that matches no VecGeom path";
139 }
140 mPrevState = mCurState;
141 return fHistory.GetTopVolume();
142}
143
144G4VPhysicalVolume* VecGeomG4PropagatingNavigator::LocateGlobalPointAndSetup(const G4ThreeVector& point,
145 const G4ThreeVector*,
146 const G4bool relativeSearch, const G4bool)
147{
148 bool onBoundary = fWasLimitedByGeometry;
149 if (mHaveNextState && point.diff2(mNextPoint) < 1.e-16) {
150 onBoundary = true;
151 }
152
153 mPrevState = mCurState;
154 mLocatedPoint = point;
155 mExitBlockPending = false;
156
157 if (!mForceReInit && relativeSearch && onBoundary && mHaveNextState) {
158 // The state on the far side of the boundary was already worked out, and relocated, by the step
159 // that found it. Adopting it is cheaper than locating again.
160 mCurState = mNextState;
161 mExitBlockPending = mWouldExit;
162 } else if (mForceReInit || !relativeSearch || onBoundary) {
163 mCurState.Clear();
164 vecgeom::GlobalLocator::LocateGlobalPoint(vecgeom::GeoManager::Instance().GetWorld(), toVG(point), mCurState, true);
165 mForceReInit = false;
166 ++mGlobalRelocates;
167 }
168 // Otherwise the point only moved inside the volume the state already names.
169
170 auto* target = historyFromState(mCurState);
171 mCrossed = onBoundary;
172 if (onBoundary) {
173 fExitedMother = mWouldExit;
174 fEnteredDaughter = mWouldEnter;
175 mOnBoundary = true;
176 }
177 mHaveNextState = false;
178 return target;
179}
180
182{
183 // The track moved inside the volume it is already in, so only the boundary flags change.
184 mWouldEnter = false;
185 mWouldExit = false;
186 mOnBoundary = false;
187 mCrossed = false;
188 mHaveNextState = false;
189 fEnteredDaughter = false;
190 fExitedMother = false;
191}
192
193G4double VecGeomG4PropagatingNavigator::ComputeSafety(const G4ThreeVector& globalPoint, const G4double, const G4bool)
194{
195 if (mZeroSafety || mOnBoundary || mCrossed || fEnteredDaughter || fExitedMother || mWouldEnter || mWouldExit) {
196 return 0.;
197 }
198 auto const* top = mCurState.Top();
199 if (top == nullptr) {
200 return 0.;
201 }
202 const double safety = top->GetLogicalVolume()->GetSafetyEstimator()->ComputeSafety(toVG(globalPoint), mCurState);
203 return (safety > 0.) ? safety * kVGToG4 : 0.;
204}
205
206G4ThreeVector VecGeomG4PropagatingNavigator::GetGlobalExitNormal(const G4ThreeVector& point, G4bool* valid)
207{
208 // The surface just crossed belongs to the volume that was left when the step exited a mother, and
209 // to the volume that was entered when it entered a daughter.
210 auto const& state = mWouldExit ? mPrevState : mCurState;
211 auto const* volume = state.Top();
212 if (volume == nullptr) {
213 *valid = false;
214 return G4ThreeVector(0., 0., 1.);
215 }
216
217 vecgeom::Transformation3D m;
218 state.TopMatrix(m);
219 V3 normal;
220 volume->Normal(m.Transform(toVG(point)), normal);
221 V3 global = m.InverseTransformDirection(normal);
222
223 // Oriented along the direction of motion, as TGeo's FindNormalFast does.
224 const V3 dir = toDir(mLastDirection);
225 if (global.Dot(dir) < 0.) {
226 global = -global;
227 }
228 // VecGeom's Normal() also answers whether the point was on the surface; Geant4 hands back points a
229 // few nanometres off the face, so only a degenerate vector is refused.
230 const double mag2 = global.Mag2();
231 *valid = std::isfinite(mag2) && mag2 > 0.25;
232 return G4ThreeVector(global[0], global[1], global[2]);
233}
234
236{
237 // By convention the local normal is expressed in the frame of the final volume.
238 const G4ThreeVector global = GetGlobalExitNormal(mNextPoint, valid);
239 vecgeom::Transformation3D m;
240 mCurState.TopMatrix(m);
241 const V3 local = m.TransformDirection(toDir(global));
242 return G4ThreeVector(local[0], local[1], local[2]);
243}
244
245} // namespace o2::simsetup
SurfaceTrackState state
bool valid
static bool directionLeaves(const V3 &n, const V3 &dir)
static V3 toDir(const G4ThreeVector &d)
G4VPhysicalVolume * historyFromState(vecgeom::NavigationState const &state)
static V3 toVG(const G4ThreeVector &p)
bool stateFromHistory(vecgeom::NavigationState &state) const
G4double ComputeSafety(const G4ThreeVector &globalPoint, const G4double proposedMaxLength=DBL_MAX, const G4bool keepState=true) override
G4double ComputeStep(const G4ThreeVector &globalPoint, const G4ThreeVector &direction, const G4double proposedStepLength, G4double &newSafety) override
G4VPhysicalVolume * LocateGlobalPointAndSetup(const G4ThreeVector &point, const G4ThreeVector *direction=nullptr, const G4bool relativeSearch=true, const G4bool ignoreDirection=true) override
G4ThreeVector GetLocalExitNormal(G4bool *valid) override
G4ThreeVector GetGlobalExitNormal(const G4ThreeVector &point, G4bool *valid) override
void LocateGlobalPointWithinVolume(const G4ThreeVector &position) override
VecGeomG4PropagatingNavigator(VecGeomG4Map const &map, bool zeroSafety)
G4VPhysicalVolume * ResetHierarchyAndLocate(const G4ThreeVector &point, const G4ThreeVector &direction, const G4TouchableHistory &history) override
const GLfloat * m
Definition glcorearb.h:4066
GLdouble GLdouble GLdouble GLdouble top
Definition glcorearb.h:4077
GLenum target
Definition glcorearb.h:1641
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"