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 <algorithm>
28#include <cmath>
29
30namespace
31{
34const double kNudge = 1.e-3;
35} // namespace
36
37namespace o2::simsetup
38{
39
41 : VecGeomG4NavigatorBase(map), mZeroSafety(zeroSafety)
42{
43 mEmptyState.Clear();
44}
45
47{
48 LOG(info) << "VecGeom navigation: " << mNudgedSteps << " stalled steps nudged forward, " << mGlobalRelocates
49 << " relocations restarted from the world";
50}
51
52G4double VecGeomG4PropagatingNavigator::ComputeStep(const G4ThreeVector& globalPoint, const G4ThreeVector& direction,
53 const G4double proposedStepLength, G4double& newSafety)
54{
55 newSafety = 0.;
56 mLastDirection = direction;
57 mHaveNextState = false;
58
59 auto const* top = mCurState.Top();
60 if (top == nullptr) { // the track is outside the world
61 mWouldEnter = mWouldExit = false;
62 return kInfinity;
63 }
64 auto const* navigator = top->GetLogicalVolume()->GetNavigator();
65
66 double limit = proposedStepLength * kG4ToVG;
67 if (!(limit < vecgeom::kInfLength)) {
68 limit = vecgeom::kInfLength;
69 }
70
71 // VecGeom's own combined entry point, rather than a step followed by a relocation of our own: it
72 // is the one that knows how to descend through an assembly, whose placed volume can never be the
73 // answer because it has no DistanceToOut.
74 // The adopted state marks the volume the crossing left. As in Geant4, it is blocked in the first
75 // step after the exit only, and only while the direction points away from it; a track turning
76 // back into it must see its boundary.
77 const bool block = mExitBlockPending && globalPoint.diff2(mLocatedPoint) < 1.e-20 &&
78 directionLeaves(mPrevState, toVG(globalPoint), toDir(direction));
79 mExitBlockPending = false;
80 if (!block) {
81 mCurState.SetLastExited(mEmptyState.GetLastExitedState());
82 }
83
84 double vgSafety = 0.;
85 const double vgStep = navigator->ComputeStepAndSafetyAndPropagatedState(
86 toVG(globalPoint), toDir(direction), limit, mCurState, mNextState, !mOnBoundary && !mZeroSafety, vgSafety);
87 mOnBoundary = false;
88 newSafety = (vgSafety > 0. && !mZeroSafety) ? vgSafety * kVGToG4 : 0.;
89
90 G4double step = vgStep * kVGToG4;
91 if (mNextState.IsOnBoundary()) {
92 // Entering a daughter deepens the state, possibly by more than one level when an assembly
93 // stands in between; leaving the current volume does not.
94 mWouldEnter = mNextState.GetCurrentLevel() > mCurState.GetCurrentLevel();
95 mWouldExit = !mWouldEnter;
96 mNextPoint = globalPoint + step * direction;
97 mHaveNextState = true;
98 } else {
99 mWouldEnter = mWouldExit = false;
100 step = kInfinity;
101 }
102
103 if (vgStep < 0.) {
104 // A negative distance means the state and the point disagree. Nudge forward and relocate from
105 // the world on the next call rather than propagating the inconsistency.
106 mForceReInit = true;
107 mHaveNextState = false;
108 ++mNudgedSteps;
109 mZeroSteps = 0;
110 return kNudge;
111 }
112 if (step < 1.e-10) {
113 if (++mZeroSteps > 4) {
114 mForceReInit = true;
115 mHaveNextState = false;
116 ++mNudgedSteps;
117 return kNudge;
118 }
119 } else {
120 mForceReInit = false;
121 mZeroSteps = 0;
122 }
123 return step;
124}
125
126G4VPhysicalVolume* VecGeomG4PropagatingNavigator::ResetHierarchyAndLocate(const G4ThreeVector&, const G4ThreeVector&,
127 const G4TouchableHistory& history)
128{
129 // Geant4 hands back a touchable it saved earlier, e.g. when resuming a track whose secondaries
130 // were followed first. The VecGeom state is rebuilt from it.
131 fEnteredDaughter = false;
132 fExitedMother = false;
133 mWouldEnter = false;
134 mWouldExit = false;
135 mOnBoundary = false;
136 mHaveNextState = false;
137 mLastSafety = -1.;
138 fHistory = *history.GetHistory();
139 if (!stateFromHistory(mCurState) && fHistory.GetVolume(0) != nullptr) {
140 LOG(fatal) << "Geant4 handed back a touchable that matches no VecGeom path";
141 }
142 mPrevState = mCurState;
143 return fHistory.GetTopVolume();
144}
145
146G4VPhysicalVolume* VecGeomG4PropagatingNavigator::LocateGlobalPointAndSetup(const G4ThreeVector& point,
147 const G4ThreeVector*,
148 const G4bool relativeSearch, const G4bool)
149{
150 bool onBoundary = fWasLimitedByGeometry;
151 if (mHaveNextState && point.diff2(mNextPoint) < 1.e-16) {
152 onBoundary = true;
153 }
154
155 mPrevState = mCurState;
156 mLocatedPoint = point;
157 mExitBlockPending = false;
158 mLastSafety = -1.;
159
160 if (!mForceReInit && relativeSearch && onBoundary && mHaveNextState) {
161 // The state on the far side of the boundary was already worked out, and relocated, by the step
162 // that found it. Adopting it is cheaper than locating again.
163 mCurState = mNextState;
164 mExitBlockPending = mWouldExit;
165 } else if (mForceReInit || !relativeSearch || onBoundary) {
166 mCurState.Clear();
167 vecgeom::GlobalLocator::LocateGlobalPoint(vecgeom::GeoManager::Instance().GetWorld(), toVG(point), mCurState, true);
168 mForceReInit = false;
169 ++mGlobalRelocates;
170 }
171 // Otherwise the point only moved inside the volume the state already names.
172
173 auto* target = historyFromState(mCurState);
174 mCrossed = onBoundary;
175 if (onBoundary) {
176 fExitedMother = mWouldExit;
177 fEnteredDaughter = mWouldEnter;
178 mOnBoundary = true;
179 }
180 mHaveNextState = false;
181 return target;
182}
183
185{
186 // The track moved inside the volume it is already in, so only the boundary flags change.
187 mWouldEnter = false;
188 mWouldExit = false;
189 mOnBoundary = false;
190 mCrossed = false;
191 mHaveNextState = false;
192 fEnteredDaughter = false;
193 fExitedMother = false;
194}
195
196G4double VecGeomG4PropagatingNavigator::ComputeSafety(const G4ThreeVector& globalPoint, const G4double proposedMaxLength,
197 const G4bool)
198{
199 if (mZeroSafety || mOnBoundary || mCrossed || fEnteredDaughter || fExitedMother || mWouldEnter || mWouldExit) {
200 return 0.;
201 }
202 if (mCurState.Top() == nullptr) {
203 return 0.;
204 }
205 // Every point closer to the last safety origin than its safety is in the same volume, so s0 - d is a
206 // valid safety there; it is used when it covers the caller's bound. Every locate drops the cache.
207 const double rest = mLastSafety - std::sqrt(globalPoint.diff2(mSafetyOrig));
208 if (rest >= proposedMaxLength) {
209 return rest;
210 }
211 mSafetyOrig = globalPoint;
212 mLastSafety = std::max(boundedSafety(mCurState, globalPoint, proposedMaxLength), 0.);
213 return mLastSafety;
214}
215
216G4ThreeVector VecGeomG4PropagatingNavigator::GetGlobalExitNormal(const G4ThreeVector& point, G4bool* valid)
217{
218 // The surface just crossed belongs to the volume that was left when the step exited a mother, and
219 // to the volume that was entered when it entered a daughter.
220 auto const& state = mWouldExit ? mPrevState : mCurState;
221 auto const* volume = state.Top();
222 if (volume == nullptr) {
223 *valid = false;
224 return G4ThreeVector(0., 0., 1.);
225 }
226
227 vecgeom::Transformation3D m;
228 state.TopMatrix(m);
229 V3 normal;
230 volume->Normal(m.Transform(toVG(point)), normal);
231 V3 global = m.InverseTransformDirection(normal);
232
233 // Oriented along the direction of motion, as TGeo's FindNormalFast does.
234 const V3 dir = toDir(mLastDirection);
235 if (global.Dot(dir) < 0.) {
236 global = -global;
237 }
238 // VecGeom's Normal() also answers whether the point was on the surface; Geant4 hands back points a
239 // few nanometres off the face, so only a degenerate vector is refused.
240 const double mag2 = global.Mag2();
241 *valid = std::isfinite(mag2) && mag2 > 0.25;
242 return G4ThreeVector(global[0], global[1], global[2]);
243}
244
246{
247 // By convention the local normal is expressed in the frame of the final volume.
248 const G4ThreeVector global = GetGlobalExitNormal(mNextPoint, valid);
249 vecgeom::Transformation3D m;
250 mCurState.TopMatrix(m);
251 const V3 local = m.TransformDirection(toDir(global));
252 return G4ThreeVector(local[0], local[1], local[2]);
253}
254
255} // 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
static double boundedSafety(vecgeom::NavigationState const &state, const G4ThreeVector &point, double limit)
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"