Geant4 11.4.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4Navigator.cc
Go to the documentation of this file.
1//
2// ********************************************************************
3// * License and Disclaimer *
4// * *
5// * The Geant4 software is copyright of the Copyright Holders of *
6// * the Geant4 Collaboration. It is provided under the terms and *
7// * conditions of the Geant4 Software License, included in the file *
8// * LICENSE and available at http://cern.ch/geant4/license . These *
9// * include a list of copyright holders. *
10// * *
11// * Neither the authors of this software system, nor their employing *
12// * institutes,nor the agencies providing financial support for this *
13// * work make any representation or warranty, express or implied, *
14// * regarding this software system or assume any liability for its *
15// * use. Please see the license in the file LICENSE and URL above *
16// * for the full disclaimer and the limitation of liability. *
17// * *
18// * This code implementation is the result of the scientific and *
19// * technical work of the GEANT4 collaboration. *
20// * By using, copying, modifying or distributing the software (or *
21// * any work based on the software) you agree to acknowledge its *
22// * use in resulting scientific publications, and indicate your *
23// * acceptance of all terms of the Geant4 Software license. *
24// ********************************************************************
25//
26// G4Navigator class Implementation
27//
28// Original author: Paul Kent (CERN), July 1995-1996
29// Responsible 1996-present: John Apostolakis, Gabriele Cosmo (CERN)
30// Additional revisions by: Pedro Arce (CIEMAT), Vladimir Grichine (CERN)
31// --------------------------------------------------------------------
32
33#include <iomanip>
34
35#include "G4Navigator.hh"
36#include "G4ios.hh"
37#include "G4SystemOfUnits.hh"
39#include "G4VPhysicalVolume.hh"
40
41#include "G4VoxelSafety.hh"
42#include "G4SafetyCalculator.hh"
43
44// Constant determining how precise normals should be (how close to unit
45// vectors). If exceeded, warnings will be issued.
46// Can be CLHEP::perMillion (its old default) for geometry checking.
47//
48static const G4double kToleranceNormalCheck = CLHEP::perThousand;
49
50// ********************************************************************
51// Constructor
52// ********************************************************************
53//
55{
57 // Initialises also all
58 // - exit / entry flags
59 // - flags & variables for exit normals
60 // - zero step counters
61 // - blocked volume
62
63 if( fVerbose > 2 )
64 {
65 G4cout << " G4Navigator parameters: Action Threshold (No Zero Steps) = "
66 << fActionThreshold_NoZeroSteps
67 << " Abandon Threshold (No Zero Steps) = "
68 << fAbandonThreshold_NoZeroSteps << G4endl;
69 }
73
74 fregularNav.SetNormalNavigation( &fnormalNav );
75
76 fStepEndPoint = G4ThreeVector( kInfinity, kInfinity, kInfinity );
77 fLastStepEndPointLocal = G4ThreeVector( kInfinity, kInfinity, kInfinity );
78
79 fpVoxelSafety = new G4VoxelSafety();
80 fpvoxelNav = new G4VoxelNavigation();
81 fpSafetyCalculator = new G4SafetyCalculator( *this, fHistory );
82 fpSafetyCalculator->SetExternalNavigation(fpExternalNav);
83}
84
85// ********************************************************************
86// Destructor
87// ********************************************************************
88//
90{
91 delete fpVoxelSafety;
92 delete fpExternalNav;
93 delete fpvoxelNav;
94 delete fpSafetyCalculator;
95}
96
97// ********************************************************************
98// ResetHierarchyAndLocate
99// ********************************************************************
100//
103 const G4ThreeVector& direction,
104 const G4TouchableHistory& h)
105{
106 ResetState();
107 fHistory = *h.GetHistory();
109 fLastTriedStepComputation = false; // Redundant, but best
110 return LocateGlobalPointAndSetup(p, &direction, true, false);
111}
112
113// ********************************************************************
114// LocateGlobalPointAndSetup
115//
116// Locate the point in the hierarchy return 0 if outside
117// The direction is required
118// - if on an edge shared by more than two surfaces
119// (to resolve likely looping in tracking)
120// - at initial location of a particle
121// (to resolve potential ambiguity at boundary)
122//
123// Flags on exit: (comments to be completed)
124// fEntering - True if entering `daughter' volume (or replica)
125// whether daughter of last mother directly
126// or daughter of that volume's ancestor.
127// fExiting - True if exited 'mother' volume
128// (always ? - how about if going back down ? - tbc)
129// ********************************************************************
130//
133 const G4ThreeVector* pGlobalDirection,
134 const G4bool relativeSearch,
135 const G4bool ignoreDirection )
136{
137 G4bool notKnownContained = true, noResult;
138 G4VPhysicalVolume *targetPhysical;
139 G4LogicalVolume *targetLogical;
140 G4VSolid *targetSolid = nullptr;
141 G4ThreeVector localPoint, globalDirection;
142 EInside insideCode;
143
144 G4bool considerDirection = (pGlobalDirection != nullptr) && ((!ignoreDirection) || fLocatedOnEdge);
145
146 fLastTriedStepComputation = false;
147 fChangedGrandMotherRefFrame = false; // For local exit normal
148
149 if( considerDirection )
150 {
151 globalDirection=*pGlobalDirection;
152 }
153
154#ifdef G4VERBOSE
155 if( fVerbose > 2 )
156 {
157 G4long oldcoutPrec = G4cout.precision(8);
158 G4cout << "*** G4Navigator::LocateGlobalPointAndSetup: ***" << G4endl;
159 G4cout << " Called with arguments: " << G4endl
160 << " Globalpoint = " << globalPoint << G4endl
161 << " RelativeSearch = " << relativeSearch << G4endl;
162 if( fVerbose >= 4 )
163 {
164 G4cout << " ----- Upon entering:" << G4endl;
165 PrintState();
166 }
167 G4cout.precision(oldcoutPrec);
168 }
169#endif
170
171 G4int noLevelsExited = 0;
172
173 if ( !relativeSearch )
174 {
176 }
177 else
178 {
180 {
181 fWasLimitedByGeometry = false;
182 fEnteredDaughter = fEntering; // Remember
183 fExitedMother = fExiting; // Remember
184 if ( fExiting )
185 {
186 ++noLevelsExited; // count this first level entered too
187
188 if ( fHistory.GetDepth() != 0 )
189 {
190 fBlockedPhysicalVolume = fHistory.GetTopVolume();
191 fBlockedReplicaNo = fHistory.GetTopReplicaNo();
192 fHistory.BackLevel();
193 }
194 else
195 {
196 fLastLocatedPointLocal = localPoint;
197 fLocatedOutsideWorld = true;
198 fBlockedPhysicalVolume = nullptr; // to be sure
199 fBlockedReplicaNo = -1;
200 fEntering = false; // No longer
201 fEnteredDaughter = false;
202 fExitedMother = true; // ??
203
204 return nullptr; // Have exited world volume
205 }
206 // A fix for the case where a volume is "entered" at an edge
207 // and a coincident surface exists outside it.
208 // - This stops it from exiting further volumes and cycling
209 // - However ReplicaNavigator treats this case itself
210 //
211 // assert( fBlockedPhysicalVolume!=0 );
212
213 // Expect to be on edge => on surface
214 //
215 if ( fLocatedOnEdge && (VolumeType(fBlockedPhysicalVolume)!=kReplica ))
216 {
217 fExiting = false;
218 // Consider effect on Exit Normal !?
219 }
220 }
221 else
222 if ( fEntering )
223 {
224 switch (VolumeType(fBlockedPhysicalVolume))
225 {
226 case kNormal:
227 fHistory.NewLevel(fBlockedPhysicalVolume, kNormal,
228 fBlockedPhysicalVolume->GetCopyNo());
229 break;
230 case kReplica:
231 freplicaNav.ComputeTransformation(fBlockedReplicaNo,
232 fBlockedPhysicalVolume);
233 fHistory.NewLevel(fBlockedPhysicalVolume, kReplica,
234 fBlockedReplicaNo);
235 fBlockedPhysicalVolume->SetCopyNo(fBlockedReplicaNo);
236 break;
237 case kParameterised:
238 if( fBlockedPhysicalVolume->GetRegularStructureId() == 0 )
239 {
240 G4VSolid *pSolid;
241 G4VPVParameterisation *pParam;
242 G4TouchableHistory parentTouchable( fHistory );
243 pParam = fBlockedPhysicalVolume->GetParameterisation();
244 pSolid = pParam->ComputeSolid(fBlockedReplicaNo,
245 fBlockedPhysicalVolume);
246 pSolid->ComputeDimensions(pParam, fBlockedReplicaNo,
247 fBlockedPhysicalVolume);
248 pParam->ComputeTransformation(fBlockedReplicaNo,
249 fBlockedPhysicalVolume);
250 fHistory.NewLevel(fBlockedPhysicalVolume, kParameterised,
251 fBlockedReplicaNo);
252 fBlockedPhysicalVolume->SetCopyNo(fBlockedReplicaNo);
253 //
254 // Set the correct solid and material in Logical Volume
255 //
256 G4LogicalVolume *pLogical;
257 pLogical = fBlockedPhysicalVolume->GetLogicalVolume();
258 pLogical->SetSolid( pSolid );
259 pLogical->UpdateMaterial(pParam ->
260 ComputeMaterial(fBlockedReplicaNo,
261 fBlockedPhysicalVolume,
262 &parentTouchable));
263 }
264 break;
265 case kExternal:
266 G4Exception("G4Navigator::LocateGlobalPointAndSetup()",
267 "GeomNav0001", FatalException,
268 "Extra levels not applicable for external volumes.");
269 break;
270 }
271 fEntering = false;
272 fBlockedPhysicalVolume = nullptr;
273 localPoint = fHistory.GetTopTransform().TransformPoint(globalPoint);
274 notKnownContained = false;
275 }
276 }
277 else
278 {
279 fBlockedPhysicalVolume = nullptr;
280 fEntering = false;
281 fEnteredDaughter = false; // Full Step was not taken, did not enter
282 fExiting = false;
283 fExitedMother = false; // Full Step was not taken, did not exit
284 }
285 }
286 //
287 // Search from top of history up through geometry until
288 // containing volume found:
289 // If on
290 // o OUTSIDE - Back up level, not/no longer exiting volumes
291 // o SURFACE and EXITING - Back up level, setting new blocking no.s
292 // else
293 // o containing volume found
294 //
295
296 while (notKnownContained) // Loop checking, 07.10.2016, J.Apostolakis
297 {
298 EVolume topVolumeType = fHistory.GetTopVolumeType();
299 if (topVolumeType!=kReplica && topVolumeType!=kExternal)
300 {
301 targetSolid = fHistory.GetTopVolume()->GetLogicalVolume()->GetSolid();
302 localPoint = fHistory.GetTopTransform().TransformPoint(globalPoint);
303 insideCode = targetSolid->Inside(localPoint);
304#ifdef G4VERBOSE
305 if(( fVerbose == 1 ) && ( fCheck ))
306 {
307 G4String solidResponse = "-kInside-";
308 if (insideCode == kOutside)
309 {
310 solidResponse = "-kOutside-";
311 }
312 else if (insideCode == kSurface)
313 {
314 solidResponse = "-kSurface-";
315 }
316 G4cout << "*** G4Navigator::LocateGlobalPointAndSetup(): ***" << G4endl
317 << " Invoked Inside() for solid: " << targetSolid->GetName()
318 << ". Solid replied: " << solidResponse << G4endl
319 << " For local point p: " << localPoint << G4endl;
320 }
321#endif
322 }
323 else
324 {
325 if( topVolumeType == kReplica )
326 {
327 insideCode = freplicaNav.BackLocate(fHistory, globalPoint, localPoint,
328 fExiting, notKnownContained);
329 // !CARE! if notKnownContained returns false then the point is within
330 // the containing placement volume of the replica(s). If insidecode
331 // will result in the history being backed up one level, then the
332 // local point returned is the point in the system of this new level
333 }
334 else
335 {
336 targetSolid = fHistory.GetTopVolume()->GetLogicalVolume()->GetSolid();
337 localPoint = fHistory.GetTopTransform().TransformPoint(globalPoint);
338 G4ThreeVector localDirection =
339 fHistory.GetTopTransform().TransformAxis(globalDirection);
340 insideCode = fpExternalNav->Inside(targetSolid, localPoint, localDirection);
341 }
342 }
343
344 // Point is inside current volume, break out of the loop
345 if ( insideCode == kInside ) { break; }
346
347 // Point is outside current volume, move up a level in the hierarchy
348 if ( insideCode == kOutside )
349 {
350 ++noLevelsExited;
351
352 // Exiting world volume
353 if ( fHistory.GetDepth() == 0 )
354 {
355 fLocatedOutsideWorld = true;
356 fLastLocatedPointLocal = localPoint;
357 return nullptr;
358 }
359
360 fBlockedPhysicalVolume = fHistory.GetTopVolume();
361 fBlockedReplicaNo = fHistory.GetTopReplicaNo();
362 fHistory.BackLevel();
363 fExiting = false;
364
365 if( noLevelsExited > 1 )
366 {
367 // The first transformation was done by the sub-navigator
368 //
369 if(const auto *mRot = fBlockedPhysicalVolume->GetRotation())
370 {
371 fGrandMotherExitNormal *= (*mRot).inverse();
372 fChangedGrandMotherRefFrame = true;
373 }
374 }
375 continue;
376 }
377
378 // Point is on the surface of a volume
379 G4bool isExiting = fExiting;
380 if( (!fExiting) && considerDirection )
381 {
382 // Figure out whether we are exiting this level's volume
383 // by using the direction
384 //
385 G4bool directionExiting = false;
386 G4ThreeVector localDirection =
387 fHistory.GetTopTransform().TransformAxis(globalDirection);
388
389 // Make sure localPoint in correct reference frame
390 // ( Was it already correct ? How ? )
391 //
392 localPoint= fHistory.GetTopTransform().TransformPoint(globalPoint);
393 if ( fHistory.GetTopVolumeType() != kReplica )
394 {
395 G4ThreeVector normal = targetSolid->SurfaceNormal(localPoint);
396 directionExiting = normal.dot(localDirection) > 0.0;
397 isExiting = isExiting || directionExiting;
398 }
399 }
400
401 // Point is on a surface, but no longer exiting, break out of the loop
402 if ( !isExiting ) { break; }
403
404 ++noLevelsExited;
405
406 // Point is on the outer surface, leaving world volume
407 if ( fHistory.GetDepth() == 0 )
408 {
409 fLocatedOutsideWorld = true;
410 fLastLocatedPointLocal = localPoint;
411 return nullptr;
412 }
413
414 // Point is still on a surface, but exited a volume not necessarily convex
415 fValidExitNormal = false;
416 fBlockedPhysicalVolume = fHistory.GetTopVolume();
417 fBlockedReplicaNo = fHistory.GetTopReplicaNo();
418 fHistory.BackLevel();
419
420 if( noLevelsExited > 1 )
421 {
422 // The first transformation was done by the sub-navigator
423 //
424 const G4RotationMatrix* mRot =
425 fBlockedPhysicalVolume->GetRotation();
426 if( mRot != nullptr )
427 {
428 fGrandMotherExitNormal *= (*mRot).inverse();
429 fChangedGrandMotherRefFrame = true;
430 }
431 }
432 } // END while (notKnownContained)
433 //
434 // Search downwards until deepest containing volume found,
435 // blocking fBlockedPhysicalVolume/BlockedReplicaNum
436 //
437 // 3 Cases:
438 //
439 // o Parameterised daughters
440 // =>Must be one G4PVParameterised daughter & voxels
441 // o Positioned daughters & voxels
442 // o Positioned daughters & no voxels
443
444 noResult = true; // noResult should be renamed to
445 // something like enteredLevel, as that is its meaning.
446 do
447 {
448 // Determine `type' of current mother volume
449 //
450 targetPhysical = fHistory.GetTopVolume();
451 if (targetPhysical == nullptr) { break; }
452 targetLogical = targetPhysical->GetLogicalVolume();
453 switch( CharacteriseDaughters(targetLogical) )
454 {
455 case kNormal:
456 if ( targetLogical->GetVoxelHeader() != nullptr ) // use optimised navigation
457 {
459 fBlockedPhysicalVolume,
460 fBlockedReplicaNo,
461 globalPoint,
462 pGlobalDirection,
463 considerDirection,
464 localPoint);
465 }
466 else // do not use optimised navigation
467 {
468 noResult = fnormalNav.LevelLocate(fHistory,
469 fBlockedPhysicalVolume,
470 fBlockedReplicaNo,
471 globalPoint,
472 pGlobalDirection,
473 considerDirection,
474 localPoint);
475 }
476 break;
477 case kReplica:
478 noResult = freplicaNav.LevelLocate(fHistory,
479 fBlockedPhysicalVolume,
480 fBlockedReplicaNo,
481 globalPoint,
482 pGlobalDirection,
483 considerDirection,
484 localPoint);
485 break;
486 case kParameterised:
487 if( GetDaughtersRegularStructureId(targetLogical) != 1 )
488 {
489 noResult = fparamNav.LevelLocate(fHistory,
490 fBlockedPhysicalVolume,
491 fBlockedReplicaNo,
492 globalPoint,
493 pGlobalDirection,
494 considerDirection,
495 localPoint);
496 }
497 else // Regular structure
498 {
499 noResult = fregularNav.LevelLocate(fHistory,
500 fBlockedPhysicalVolume,
501 fBlockedReplicaNo,
502 globalPoint,
503 pGlobalDirection,
504 considerDirection,
505 localPoint);
506 }
507 break;
508 case kExternal:
509 noResult = fpExternalNav->LevelLocate(fHistory,
510 fBlockedPhysicalVolume,
511 fBlockedReplicaNo,
512 globalPoint,
513 pGlobalDirection,
514 considerDirection,
515 localPoint);
516 break;
517 }
518
519 // LevelLocate returns true if it finds a daughter volume
520 // in which globalPoint is inside (or on the surface).
521
522 if ( noResult )
523 {
524 // Entering a daughter after ascending
525 //
526 // The blocked volume is no longer valid - it was for another level
527 //
528 fBlockedPhysicalVolume = nullptr;
529 fBlockedReplicaNo = -1;
530
531 // fEntering should be false -- else blockedVolume is assumed good.
532 // fEnteredDaughter is used for ExitNormal
533 //
534 fEntering = false;
535 fEnteredDaughter = true;
536
537 if( fExitedMother )
538 {
539 G4VPhysicalVolume* enteredPhysical = fHistory.GetTopVolume();
540 const G4RotationMatrix* mRot = enteredPhysical->GetRotation();
541 if( mRot != nullptr )
542 {
543 // Go deeper, i.e. move 'down' in the hierarchy
544 // Apply direct rotation, not inverse
545 //
546 fGrandMotherExitNormal *= (*mRot);
547 fChangedGrandMotherRefFrame= true;
548 }
549 }
550
551#ifdef G4DEBUG_NAVIGATION
552 if( fVerbose > 2 )
553 {
554 G4VPhysicalVolume* enteredPhysical = fHistory.GetTopVolume();
555 G4cout << "*** G4Navigator::LocateGlobalPointAndSetup() ***" << G4endl;
556 G4cout << " Entering volume: " << enteredPhysical->GetName()
557 << G4endl;
558 }
559#endif
560 }
561 } while (noResult); // Loop checking, 07.10.2016, J.Apostolakis
562
563 fLastLocatedPointLocal = localPoint;
564
565#ifdef G4VERBOSE
566 if( fVerbose >= 4 )
567 {
568 G4long oldcoutPrec = G4cout.precision(8);
569 G4String curPhysVol_Name("None");
570 if (targetPhysical != nullptr) { curPhysVol_Name = targetPhysical->GetName(); }
571 G4cout << " Return value = new volume = " << curPhysVol_Name << G4endl;
572 G4cout << " ----- Upon exiting:" << G4endl;
573 PrintState();
574 if( fVerbose >= 5 )
575 {
576 G4cout << "Upon exiting LocateGlobalPointAndSetup():" << G4endl;
577 G4cout << " History = " << G4endl << fHistory << G4endl << G4endl;
578 }
579 G4cout.precision(oldcoutPrec);
580 }
581#endif
582
583 fLocatedOutsideWorld = false;
584
585 return targetPhysical;
586}
587
588// ********************************************************************
589// LocateGlobalPointWithinVolume
590//
591// -> the state information of this Navigator and its subNavigators
592// is updated in order to start the next step at pGlobalpoint
593// -> no check is performed whether pGlobalpoint is inside the
594// original volume (this must be the case).
595//
596// Note: a direction could be added to the arguments, to aid in future
597// optional checking (via the old code below, flagged by OLD_LOCATE).
598// [ This would be done only in verbose mode ]
599// ********************************************************************
600//
601void
603{
604#ifdef G4DEBUG_NAVIGATION
605 assert( !fWasLimitedByGeometry );
606 // Check: Either step was not limited by a boundary or
607 // else the full step is no longer being taken
608#endif
609
610 fLastLocatedPointLocal = ComputeLocalPoint(pGlobalpoint);
611 fLastTriedStepComputation = false;
612 fChangedGrandMotherRefFrame = false; // Frame for Exit Normal
613
614 // For the case of Voxel (or Parameterised) volume the respective
615 // Navigator must be messaged to update its voxel information etc
616
617 // Update the state of the Sub Navigators
618 // - in particular any voxel information they store/cache
619 //
620 G4VPhysicalVolume* motherPhysical = fHistory.GetTopVolume();
621 G4LogicalVolume* motherLogical = motherPhysical->GetLogicalVolume();
622
623 switch( CharacteriseDaughters(motherLogical) )
624 {
625 case kNormal:
626 GetVoxelNavigator().RelocateWithinVolume( motherPhysical, fLastLocatedPointLocal );
627 break;
628 case kParameterised:
629 fparamNav.RelocateWithinVolume( motherPhysical, fLastLocatedPointLocal );
630 break;
631 case kReplica:
632 // Nothing to do
633 break;
634 case kExternal:
635 fpExternalNav->RelocateWithinVolume( motherPhysical,
636 fLastLocatedPointLocal );
637 break;
638 }
639
640 // Reset the state variables
641 // - which would have been affected
642 // by the 'equivalent' call to LocateGlobalPointAndSetup
643 // - who's values have been invalidated by the 'move'.
644 //
645 fBlockedPhysicalVolume = nullptr;
646 fBlockedReplicaNo = -1;
647 fEntering = false;
648 fEnteredDaughter = false; // Boundary not encountered, did not enter
649 fExiting = false;
650 fExitedMother = false; // Boundary not encountered, did not exit
651}
652
653// ********************************************************************
654// SetSavedState
655//
656// Save the state, in case this is a parasitic call
657// Save fValidExitNormal, fExitNormal, fExiting, fEntering,
658// fBlockedPhysicalVolume, fBlockedReplicaNo, fLastStepWasZero,
659// fLastLocatedPointLocal, fLocatedOutsideWorld, fEnteredDaughter,
660// fExitedMother, fPreviousSftOrigin, fPreviousSafety.
661// ********************************************************************
662//
664{
665 // Note: the state of dependent objects is not currently saved.
666 // ( This means that the full state is changed by calls between
667 // SetSavedState() and RestoreSavedState();
668
669 fSaveState.sExitNormal = fExitNormal;
670 fSaveState.sValidExitNormal = fValidExitNormal;
671 fSaveState.sExiting = fExiting;
672 fSaveState.sEntering = fEntering;
673
674 fSaveState.spBlockedPhysicalVolume = fBlockedPhysicalVolume;
675 fSaveState.sBlockedReplicaNo = fBlockedReplicaNo;
676
677 fSaveState.sLastStepWasZero = static_cast<G4int>(fLastStepWasZero);
678
679 fSaveState.sLocatedOutsideWorld = fLocatedOutsideWorld;
680 fSaveState.sLastLocatedPointLocal = fLastLocatedPointLocal;
681 fSaveState.sEnteredDaughter = fEnteredDaughter;
682 fSaveState.sExitedMother = fExitedMother;
683 fSaveState.sWasLimitedByGeometry = fWasLimitedByGeometry;
684
685 // Even the safety sphere - if you want to change it do it explicitly!
686 //
687 fSaveState.sPreviousSftOrigin = fPreviousSftOrigin;
688 fSaveState.sPreviousSafety = fPreviousSafety;
689}
690
691// ********************************************************************
692// RestoreSavedState
693//
694// Restore the state (in Compute Step), in case this is a parasitic call
695// ********************************************************************
696//
698{
699 fExitNormal = fSaveState.sExitNormal;
700 fValidExitNormal = fSaveState.sValidExitNormal;
701 fExiting = fSaveState.sExiting;
702 fEntering = fSaveState.sEntering;
703
704 fBlockedPhysicalVolume = fSaveState.spBlockedPhysicalVolume;
705 fBlockedReplicaNo = fSaveState.sBlockedReplicaNo;
706
707 fLastStepWasZero = (fSaveState.sLastStepWasZero != 0);
708
709 fLocatedOutsideWorld = fSaveState.sLocatedOutsideWorld;
710 fLastLocatedPointLocal = fSaveState.sLastLocatedPointLocal;
711 fEnteredDaughter = fSaveState.sEnteredDaughter;
712 fExitedMother = fSaveState.sExitedMother;
713 fWasLimitedByGeometry = fSaveState.sWasLimitedByGeometry;
714
715 // The 'expected' behaviour is to restore these too (fix 2014.05.26)
716 fPreviousSftOrigin = fSaveState.sPreviousSftOrigin;
717 fPreviousSafety = fSaveState.sPreviousSafety;
718}
719
720// ********************************************************************
721// ComputeStep
722//
723// Computes the next geometric Step: intersections with current
724// mother and `daughter' volumes.
725//
726// NOTE:
727//
728// Flags on entry:
729// --------------
730// fValidExitNormal - Normal of exited volume is valid (convex, not a
731// coincident boundary)
732// fExitNormal - Surface normal of exited volume
733// fExiting - True if have exited solid
734//
735// fBlockedPhysicalVolume - Ptr to exited volume (or 0)
736// fBlockedReplicaNo - Replication no of exited volume
737// fLastStepWasZero - True if last Step size was almost zero.
738//
739// Flags on exit:
740// -------------
741// fValidExitNormal - True if surface normal of exited volume is valid
742// fExitNormal - Surface normal of exited volume rotated to mothers
743// reference system
744// fExiting - True if exiting mother
745// fEntering - True if entering `daughter' volume (or replica)
746// fBlockedPhysicalVolume - Ptr to candidate (entered) volume
747// fBlockedReplicaNo - Replication no of candidate (entered) volume
748// fLastStepWasZero - True if this Step size was almost zero.
749// ********************************************************************
750//
752 const G4ThreeVector& pDirection,
753 const G4double pCurrentProposedStepLength,
754 G4double& pNewSafety)
755{
756#ifdef G4DEBUG_NAVIGATION
757 static G4ThreadLocal G4int sNavCScalls = 0;
758 ++sNavCScalls;
759#endif
760
761 G4ThreeVector localDirection = ComputeLocalAxis(pDirection);
762 G4double Step = kInfinity;
763 G4VPhysicalVolume *motherPhysical = fHistory.GetTopVolume();
764 G4LogicalVolume *motherLogical = motherPhysical->GetLogicalVolume();
765
766 // All state relating to exiting normals must be reset
767 //
768 fExitNormalGlobalFrame = G4ThreeVector( 0., 0., 0.);
769 // Reset value - to erase its memory
770 fChangedGrandMotherRefFrame = false;
771 // Reset - used for local exit normal
772 fGrandMotherExitNormal = G4ThreeVector( 0., 0., 0.);
773 fCalculatedExitNormal = false;
774 // Reset for new step
775
776#ifdef G4VERBOSE
777 if( fVerbose > 0 )
778 {
779 G4cout << "*** G4Navigator::ComputeStep: ***" << G4endl;
780 G4cout << " Volume = " << motherPhysical->GetName()
781 << " - Proposed step length = " << pCurrentProposedStepLength
782 << G4endl;
783#ifdef G4DEBUG_NAVIGATION
784 if( fVerbose >= 2 )
785 {
786 G4cout << " Called with the arguments: " << G4endl
787 << " Globalpoint = " << std::setw(25) << pGlobalpoint << G4endl
788 << " Direction = " << std::setw(25) << pDirection << G4endl;
789 if( fVerbose >= 4 )
790 {
791 G4cout << " ---- Upon entering : State" << G4endl;
792 PrintState();
793 }
794 }
795#endif
796 }
797#endif
798
799 G4ThreeVector newLocalPoint = ComputeLocalPoint(pGlobalpoint);
800
801 if( newLocalPoint != fLastLocatedPointLocal )
802 {
803 // Check whether the relocation is within safety
804 //
805 G4ThreeVector oldLocalPoint = fLastLocatedPointLocal;
806 G4double moveLenSq = (newLocalPoint-oldLocalPoint).mag2();
807
808 if ( moveLenSq >= fSqTol )
809 {
810#ifdef G4VERBOSE
811 ComputeStepLog(pGlobalpoint, moveLenSq);
812#endif
813 // Relocate the point within the same volume
814 //
815 LocateGlobalPointWithinVolume( pGlobalpoint );
816 }
817 }
818 if ( fHistory.GetTopVolumeType()!=kReplica )
819 {
820 switch( CharacteriseDaughters(motherLogical) )
821 {
822 case kNormal:
823 if ( motherLogical->GetVoxelHeader() != nullptr )
824 {
825 Step = GetVoxelNavigator().ComputeStep(fLastLocatedPointLocal,
826 localDirection,
827 pCurrentProposedStepLength,
828 pNewSafety,
829 fHistory,
830 fValidExitNormal,
831 fExitNormal,
832 fExiting,
833 fEntering,
834 &fBlockedPhysicalVolume,
835 fBlockedReplicaNo);
836
837 }
838 else
839 {
840 if( motherPhysical->GetRegularStructureId() == 0 )
841 {
842 Step = fnormalNav.ComputeStep(fLastLocatedPointLocal,
843 localDirection,
844 pCurrentProposedStepLength,
845 pNewSafety,
846 fHistory,
847 fValidExitNormal,
848 fExitNormal,
849 fExiting,
850 fEntering,
851 &fBlockedPhysicalVolume,
852 fBlockedReplicaNo);
853 }
854 else // Regular (non-voxelised) structure
855 {
856 LocateGlobalPointAndSetup( pGlobalpoint, &pDirection, true, true );
857 //
858 // if physical process limits the step, the voxel will not be the
859 // one given by ComputeStepSkippingEqualMaterials() and the local
860 // point will be wrongly calculated.
861
862 // There is a problem: when msc limits the step and the point is
863 // assigned wrongly to phantom in previous step (while it is out
864 // of the container volume). Then LocateGlobalPointAndSetup() has
865 // reset the history topvolume to world.
866 //
867 if(fHistory.GetTopVolume()->GetRegularStructureId() == 0 )
868 {
869 G4Exception("G4Navigator::ComputeStep()",
870 "GeomNav1001", JustWarning,
871 "Point is relocated in voxels, while it should be outside!");
872 Step = fnormalNav.ComputeStep(fLastLocatedPointLocal,
873 localDirection,
874 pCurrentProposedStepLength,
875 pNewSafety,
876 fHistory,
877 fValidExitNormal,
878 fExitNormal,
879 fExiting,
880 fEntering,
881 &fBlockedPhysicalVolume,
882 fBlockedReplicaNo);
883 }
884 else
885 {
886 Step = fregularNav.
887 ComputeStepSkippingEqualMaterials(fLastLocatedPointLocal,
888 localDirection,
889 pCurrentProposedStepLength,
890 pNewSafety,
891 fHistory,
892 fValidExitNormal,
893 fExitNormal,
894 fExiting,
895 fEntering,
896 &fBlockedPhysicalVolume,
897 fBlockedReplicaNo,
898 motherPhysical);
899 }
900 }
901 }
902 break;
903 case kParameterised:
904 if( GetDaughtersRegularStructureId(motherLogical) != 1 )
905 {
906 Step = fparamNav.ComputeStep(fLastLocatedPointLocal,
907 localDirection,
908 pCurrentProposedStepLength,
909 pNewSafety,
910 fHistory,
911 fValidExitNormal,
912 fExitNormal,
913 fExiting,
914 fEntering,
915 &fBlockedPhysicalVolume,
916 fBlockedReplicaNo);
917 }
918 else // Regular structure
919 {
920 Step = fregularNav.ComputeStep(fLastLocatedPointLocal,
921 localDirection,
922 pCurrentProposedStepLength,
923 pNewSafety,
924 fHistory,
925 fValidExitNormal,
926 fExitNormal,
927 fExiting,
928 fEntering,
929 &fBlockedPhysicalVolume,
930 fBlockedReplicaNo);
931 }
932 break;
933 case kReplica:
934 G4Exception("G4Navigator::ComputeStep()", "GeomNav0001",
935 FatalException, "Not applicable for replicated volumes.");
936 break;
937 case kExternal:
938 Step = fpExternalNav->ComputeStep(fLastLocatedPointLocal,
939 localDirection,
940 pCurrentProposedStepLength,
941 pNewSafety,
942 fHistory,
943 fValidExitNormal,
944 fExitNormal,
945 fExiting,
946 fEntering,
947 &fBlockedPhysicalVolume,
948 fBlockedReplicaNo);
949 break;
950 }
951 }
952 else
953 {
954 // In the case of a replica, it must handle the exiting
955 // edge/corner problem by itself
956 //
957 fExiting = fExitedMother;
958 Step = freplicaNav.ComputeStep(pGlobalpoint,
959 pDirection,
960 fLastLocatedPointLocal,
961 localDirection,
962 pCurrentProposedStepLength,
963 pNewSafety,
964 fHistory,
965 fValidExitNormal,
966 fCalculatedExitNormal,
967 fExitNormal,
968 fExiting,
969 fEntering,
970 &fBlockedPhysicalVolume,
971 fBlockedReplicaNo);
972 }
973
974 // Remember last safety origin & value.
975 //
976 fPreviousSftOrigin = pGlobalpoint;
977 fPreviousSafety = pNewSafety;
978
979 // Count zero steps - one can occur due to changing momentum at a boundary
980 // - one, two (or a few) can occur at common edges between
981 // volumes
982 // - more than two is likely a problem in the geometry
983 // description or the Navigation
984
985 // Rule of thumb: likely at an Edge if two consecutive steps are zero,
986 // because at least two candidate volumes must have been
987 // checked
988 //
989 fLocatedOnEdge = fLastStepWasZero && (Step==0.0);
990 fLastStepWasZero = (Step<fMinStep);
991 if (fPushed) { fPushed = fLastStepWasZero; }
992
993 // Handle large number of consecutive zero steps
994 //
995 if ( fLastStepWasZero )
996 {
997 ++fNumberZeroSteps;
998
999 G4bool act = fNumberZeroSteps >= fActionThreshold_NoZeroSteps;
1000 G4bool actAndReport = false;
1001 G4bool abandon = fNumberZeroSteps >= fAbandonThreshold_NoZeroSteps;
1002 G4bool inform = false;
1003#ifdef G4VERBOSE
1004 actAndReport = act && (!fPushed) && fWarnPush;
1005#endif
1006#ifdef G4DEBUG_NAVIGATION
1007 inform = fNumberZeroSteps > 1;
1008#endif
1009
1010 if ( act || inform )
1011 {
1012 if( act && !abandon )
1013 {
1014 // Act to recover this stuck track. Pushing it along original direction
1015 //
1016 Step += 100*kCarTolerance;
1017 fPushed = true;
1018 }
1019
1020 if( actAndReport || abandon || inform )
1021 {
1022 std::ostringstream message;
1023
1024 message.precision(16);
1025 message << "Stuck Track: potential geometry or navigation problem."
1026 << G4endl;
1027 message << " Track stuck, not moving for "
1028 << fNumberZeroSteps << " steps." << G4endl
1029 << " Current phys volume: '" << motherPhysical->GetName()
1030 << "'" << G4endl
1031 << " - at position : " << pGlobalpoint << G4endl
1032 << " in direction: " << pDirection << G4endl
1033 << " (local position: " << newLocalPoint << ")" << G4endl
1034 << " (local direction: " << localDirection << ")." << G4endl
1035 << " Previous phys volume: '"
1036 << ( fLastMotherPhys != nullptr ? fLastMotherPhys->GetName() : G4String("") )
1037 << "'" << G4endl << G4endl;
1038 if( actAndReport || abandon )
1039 {
1040 message << " Likely geometry overlap - else navigation problem !"
1041 << G4endl;
1042 }
1043 if( abandon ) // i.e. fNumberZeroSteps >= fAbandonThreshold_NoZeroSteps
1044 {
1045 // Must kill this stuck track
1046#ifdef G4VERBOSE
1047 if ( fWarnPush ) { CheckOverlapsIterative(motherPhysical); }
1048#endif
1049 message << " Track *abandoned* due to excessive number of Zero steps."
1050 << " Event aborted. " << G4endl << G4endl;
1051 G4Exception("G4Navigator::ComputeStep()", "GeomNav0003",
1052 EventMustBeAborted, message);
1053 }
1054 else
1055 {
1056#ifdef G4VERBOSE
1057 if ( actAndReport ) // (!fPushed => !wasPushed) && (fWarnPush))
1058 {
1059 message << " *** Trying to get *unstuck* using a push"
1060 << " - expanding step to " << Step << " (mm) ..."
1061 << " Potential overlap in geometry !" << G4endl;
1062 G4Exception("G4Navigator::ComputeStep()", "GeomNav1002",
1063 JustWarning, message);
1064 }
1065#endif
1066#ifdef G4DEBUG_NAVIGATION
1067 else
1068 {
1069 if( fNumberZeroSteps > 1 )
1070 {
1071 message << ", nav-comp-step calls # " << sNavCScalls
1072 << ", Step= " << Step << G4endl;
1073 G4cout << message.str();
1074 }
1075 }
1076#endif
1077 } // end of else if ( abandon )
1078 } // end of if( actAndReport || abandon || inform )
1079 } // end of if ( act || inform )
1080 }
1081 else
1082 {
1083 if (!fPushed) { fNumberZeroSteps = 0; }
1084 }
1085 fLastMotherPhys = motherPhysical;
1086
1087 fEnteredDaughter = fEntering; // I expect to enter a volume in this Step
1088 fExitedMother = fExiting;
1089
1090 fStepEndPoint = pGlobalpoint
1091 + std::min(Step,pCurrentProposedStepLength) * pDirection;
1092 fLastStepEndPointLocal = fLastLocatedPointLocal + Step * localDirection;
1093
1094 if( fExiting )
1095 {
1096#ifdef G4DEBUG_NAVIGATION
1097 if( fVerbose > 2 )
1098 {
1099 G4cout << " At G4Nav CompStep End - if(exiting) - fExiting= " << fExiting
1100 << " fValidExitNormal = " << fValidExitNormal << G4endl;
1101 G4cout << " fExitNormal= " << fExitNormal << G4endl;
1102 }
1103#endif
1104
1105 if ( fValidExitNormal || fCalculatedExitNormal )
1106 {
1107 // Convention: fExitNormal is in the 'grand-mother' coordinate system
1108 fGrandMotherExitNormal = fExitNormal;
1109 }
1110 else
1111 {
1112 // We must calculate the normal anyway (in order to have it if requested)
1113 //
1114 G4ThreeVector finalLocalPoint = fLastLocatedPointLocal
1115 + localDirection*Step;
1116
1117 if ( fHistory.GetTopVolumeType() != kReplica )
1118 {
1119 // Find normal in the 'mother' coordinate system
1120 //
1121 G4ThreeVector exitNormalMotherFrame=
1122 motherLogical->GetSolid()->SurfaceNormal(finalLocalPoint);
1123
1124 // Transform it to the 'grand-mother' coordinate system
1125 //
1126 const G4RotationMatrix* mRot = motherPhysical->GetRotation();
1127 if( mRot != nullptr )
1128 {
1129 fChangedGrandMotherRefFrame = true;
1130 fGrandMotherExitNormal = (*mRot).inverse() * exitNormalMotherFrame;
1131 }
1132 else
1133 {
1134 fGrandMotherExitNormal = exitNormalMotherFrame;
1135 }
1136
1137 // Do not set fValidExitNormal -- this signifies
1138 // that the solid is convex!
1139 }
1140 else
1141 {
1142 fCalculatedExitNormal = false;
1143 //
1144 // Nothing can be done at this stage currently - to solve this
1145 // Replica Navigation must have calculated the normal for this case
1146 // already.
1147 // Cases: mother is not convex, and exit is at previous replica level
1148
1149#ifdef G4DEBUG_NAVIGATION
1151
1152 desc << "Problem in ComputeStep: Replica Navigation did not provide"
1153 << " valid exit Normal. " << G4endl;
1154 desc << " Do not know how calculate it in this case." << G4endl;
1155 desc << " Location = " << finalLocalPoint << G4endl;
1156 desc << " Volume name = " << motherPhysical->GetName()
1157 << " copy/replica No = " << motherPhysical->GetCopyNo() << G4endl;
1158 G4Exception("G4Navigator::ComputeStep()", "GeomNav0003",
1159 JustWarning, desc, "Normal not available for exiting.");
1160#endif
1161 }
1162 }
1163
1164 if ( fHistory.GetTopVolumeType() != kReplica )
1165 {
1166 fCalculatedExitNormal = true;
1167 }
1168
1169 // Now transform it to the global reference frame !!
1170 //
1171 if( fValidExitNormal || fCalculatedExitNormal )
1172 {
1173 auto depth = (G4int)fHistory.GetDepth();
1174 if( depth > 0 )
1175 {
1176 fExitNormalGlobalFrame = fHistory.GetTransform(depth-1)
1177 .InverseTransformAxis( fGrandMotherExitNormal );
1178 }
1179 else
1180 {
1181 fExitNormalGlobalFrame = fGrandMotherExitNormal;
1182 }
1183 }
1184 else
1185 {
1186 fExitNormalGlobalFrame = G4ThreeVector( 0., 0., 0.);
1187 }
1188 }
1189
1190 if( (Step == pCurrentProposedStepLength) && (!fExiting) && (!fEntering) )
1191 {
1192 // This if Step is not really limited by the geometry.
1193 // The Navigator is obliged to return "infinity"
1194 //
1195 Step = kInfinity;
1196 }
1197
1198#ifdef G4VERBOSE
1199 if( fVerbose > 1 )
1200 {
1201 if( fVerbose >= 4 )
1202 {
1203 G4cout << " ----- Upon exiting :" << G4endl;
1204 PrintState();
1205 }
1206 G4cout << " Returned step= " << Step;
1207 if( fVerbose > 5 ) { G4cout << G4endl; }
1208 if( Step == kInfinity )
1209 {
1210 G4cout << " Requested step= " << pCurrentProposedStepLength ;
1211 if( fVerbose > 5) { G4cout << G4endl; }
1212 }
1213 G4cout << " Safety = " << pNewSafety << G4endl;
1214 }
1215#endif
1216
1217 fLastTriedStepComputation = true;
1218
1219 return Step;
1220}
1221
1222// ********************************************************************
1223// CheckNextStep
1224//
1225// Compute the step without altering the navigator state
1226// ********************************************************************
1227//
1229 const G4ThreeVector& pDirection,
1230 const G4double pCurrentProposedStepLength,
1231 G4double& pNewSafety)
1232{
1233 G4double step;
1234
1235 // Save the state, for this parasitic call
1236 //
1237 SetSavedState();
1238
1239 step = ComputeStep ( pGlobalpoint,
1240 pDirection,
1241 pCurrentProposedStepLength,
1242 pNewSafety );
1243
1244 // It is a parasitic call, so attempt to restore the key parts of the state
1245 //
1247 // NOTE: the state of the current subnavigator is NOT restored.
1248 // ***> TODO: restore subnavigator state
1249 // if( last_located) Need Position of last location
1250 // if( last_computed step) Need Endposition of last step
1251
1252 return step;
1253}
1254
1255// ********************************************************************
1256// ResetState
1257//
1258// Resets stack and minimum of navigator state `machine'
1259// ********************************************************************
1260//
1262{
1263 fWasLimitedByGeometry = false;
1264 fEntering = false;
1265 fExiting = false;
1266 fLocatedOnEdge = false;
1267 fLastStepWasZero = false;
1268 fEnteredDaughter = false;
1269 fExitedMother = false;
1270 fPushed = false;
1271
1272 fValidExitNormal = false;
1273 fChangedGrandMotherRefFrame = false;
1274 fCalculatedExitNormal = false;
1275
1276 fExitNormal = G4ThreeVector(0,0,0);
1277 fGrandMotherExitNormal = G4ThreeVector(0,0,0);
1278 fExitNormalGlobalFrame = G4ThreeVector(0,0,0);
1279
1280 fPreviousSftOrigin = G4ThreeVector(0,0,0);
1281 fPreviousSafety = 0.0;
1282
1283 fNumberZeroSteps = 0;
1284
1285 fBlockedPhysicalVolume = nullptr;
1286 fBlockedReplicaNo = -1;
1287
1288 fLastLocatedPointLocal = G4ThreeVector( kInfinity, -kInfinity, 0.0 );
1289 fLocatedOutsideWorld = false;
1290
1291 fLastMotherPhys = nullptr;
1292}
1293
1294// ********************************************************************
1295// SetupHierarchy
1296//
1297// Renavigates & resets hierarchy described by current history
1298// o Reset volumes
1299// o Recompute transforms and/or solids of replicated/parameterised volumes
1300// ********************************************************************
1301//
1303{
1304 const auto depth = (G4int)fHistory.GetDepth();
1305 for ( auto i = 1; i <= depth; ++i )
1306 {
1307 switch ( fHistory.GetVolumeType(i) )
1308 {
1309 case kNormal:
1310 case kExternal:
1311 break;
1312 case kReplica:
1313 freplicaNav.ComputeTransformation(fHistory.GetReplicaNo(i), fHistory.GetVolume(i));
1314 break;
1315 case kParameterised:
1316 G4VPhysicalVolume* current = fHistory.GetVolume(i);
1317 G4int replicaNo = fHistory.GetReplicaNo(i);
1318 G4VPVParameterisation* pParam = current->GetParameterisation();
1319 G4VSolid* pSolid = pParam->ComputeSolid(replicaNo, current);
1320
1321 // Set up dimensions & transform in solid/physical volume
1322 //
1323 pSolid->ComputeDimensions(pParam, replicaNo, current);
1324 pParam->ComputeTransformation(replicaNo, current);
1325
1326 G4TouchableHistory* pTouchable = nullptr;
1327 if( pParam->IsNested() )
1328 {
1329 pTouchable= new G4TouchableHistory( fHistory );
1330 pTouchable->MoveUpHistory(); // Move up to the parent level
1331 // Adequate only if Nested at the Branch level (last)
1332 // To extend to other cases:
1333 // pTouchable->MoveUpHistory(cdepth-i-1);
1334 // Move to the parent level of *Current* level
1335 // Could replace this line and constructor with a revised
1336 // c-tor for History(levels to drop)
1337 }
1338 // Set up the correct solid and material in Logical Volume
1339 //
1340 G4LogicalVolume* pLogical = current->GetLogicalVolume();
1341 pLogical->SetSolid( pSolid );
1342 pLogical->UpdateMaterial( pParam ->
1343 ComputeMaterial(replicaNo, current, pTouchable) );
1344 delete pTouchable;
1345 break;
1346 }
1347 }
1348}
1349
1350// ********************************************************************
1351// GetLocalExitNormal
1352//
1353// Obtains the Normal vector to a surface (in local coordinates)
1354// pointing out of previous volume and into current volume
1355// ********************************************************************
1356//
1358{
1359 G4ThreeVector ExitNormal(0.,0.,0.);
1360 G4VSolid* currentSolid = nullptr;
1361 G4LogicalVolume* candidateLogical;
1362
1363 if ( fLastTriedStepComputation )
1364 {
1365 // use fLastLocatedPointLocal and next candidate volume
1366 //
1367 G4ThreeVector nextSolidExitNormal(0.,0.,0.);
1368
1369 if( fEntering && (fBlockedPhysicalVolume!=nullptr) )
1370 {
1371 candidateLogical = fBlockedPhysicalVolume->GetLogicalVolume();
1372 if( candidateLogical != nullptr )
1373 {
1374 // fLastStepEndPointLocal is in the coordinates of the mother
1375 // we need it in the daughter's coordinate system.
1376
1377 // The following code should also work in case of Replica
1378 {
1379 // First transform fLastLocatedPointLocal to the new daughter
1380 // coordinates
1381 //
1382 G4AffineTransform MotherToDaughterTransform=
1383 GetMotherToDaughterTransform( fBlockedPhysicalVolume,
1384 fBlockedReplicaNo,
1385 VolumeType(fBlockedPhysicalVolume) );
1386 G4ThreeVector daughterPointOwnLocal =
1387 MotherToDaughterTransform.TransformPoint( fLastStepEndPointLocal );
1388
1389 // OK if it is a parameterised volume
1390 //
1391 EInside inSideIt;
1392 G4bool onSurface;
1393 G4double safety = -1.0;
1394 currentSolid = candidateLogical->GetSolid();
1395 inSideIt = currentSolid->Inside(daughterPointOwnLocal);
1396 onSurface = (inSideIt == kSurface);
1397 if( !onSurface )
1398 {
1399 if( inSideIt == kOutside )
1400 {
1401 safety = (currentSolid->DistanceToIn(daughterPointOwnLocal));
1402 onSurface = safety < 100.0 * kCarTolerance;
1403 }
1404 else if (inSideIt == kInside )
1405 {
1406 safety = (currentSolid->DistanceToOut(daughterPointOwnLocal));
1407 onSurface = safety < 100.0 * kCarTolerance;
1408 }
1409 }
1410
1411 if( onSurface )
1412 {
1413 nextSolidExitNormal =
1414 currentSolid->SurfaceNormal(daughterPointOwnLocal);
1415
1416 // Entering the solid ==> opposite
1417 //
1418 // First flip ( ExitNormal = -nextSolidExitNormal; )
1419 // and then rotate the the normal to the frame of the mother (current volume)
1420 ExitNormal = MotherToDaughterTransform
1421 .InverseTransformAxis( -nextSolidExitNormal );
1422 fCalculatedExitNormal = true;
1423 }
1424 else
1425 {
1426#ifdef G4VERBOSE
1427 if(( fVerbose == 1 ) && ( fCheck ))
1428 {
1429 std::ostringstream message;
1430 message << "Point not on surface ! " << G4endl
1431 << " Point = "
1432 << daughterPointOwnLocal << G4endl
1433 << " Physical volume = "
1434 << fBlockedPhysicalVolume->GetName() << G4endl
1435 << " Logical volume = "
1436 << candidateLogical->GetName() << G4endl
1437 << " Solid = " << currentSolid->GetName()
1438 << " Type = "
1439 << currentSolid->GetEntityType() << G4endl
1440 << *currentSolid << G4endl;
1441 if( inSideIt == kOutside )
1442 {
1443 message << "Point is Outside. " << G4endl
1444 << " Safety (from outside) = " << safety << G4endl;
1445 }
1446 else // if( inSideIt == kInside )
1447 {
1448 message << "Point is Inside. " << G4endl
1449 << " Safety (from inside) = " << safety << G4endl;
1450 }
1451 G4Exception("G4Navigator::GetLocalExitNormal()", "GeomNav1001",
1452 JustWarning, message);
1453 }
1454#endif
1455 }
1456 *valid = onSurface; // was =true;
1457 }
1458 }
1459 }
1460 else if ( fExiting )
1461 {
1462 ExitNormal = fGrandMotherExitNormal;
1463 *valid = true;
1464 fCalculatedExitNormal = true; // Should be true already
1465 }
1466 else // i.e. ( fBlockedPhysicalVolume == 0 )
1467 {
1468 *valid = false;
1469 G4Exception("G4Navigator::GetLocalExitNormal()",
1470 "GeomNav0003", JustWarning,
1471 "Incorrect call to GetLocalSurfaceNormal." );
1472 }
1473 }
1474 else // ( ! fLastTriedStepComputation ) i.e. last call was to Locate
1475 {
1476 if ( EnteredDaughterVolume() )
1477 {
1478 G4VSolid* daughterSolid = fHistory.GetTopVolume()->GetLogicalVolume()
1479 ->GetSolid();
1480 ExitNormal = -(daughterSolid->SurfaceNormal(fLastLocatedPointLocal));
1481 if( std::fabs(ExitNormal.mag2()-1.0 ) > kToleranceNormalCheck )
1482 {
1484 desc << " Parameters of solid: " << *daughterSolid
1485 << " Point for surface = " << fLastLocatedPointLocal << std::endl;
1486 G4Exception("G4Navigator::GetLocalExitNormal()",
1487 "GeomNav0003", FatalException, desc,
1488 "Surface Normal returned by Solid is not a Unit Vector." );
1489 }
1490 fCalculatedExitNormal = true;
1491 *valid = true;
1492 }
1493 else
1494 {
1495 if( fExitedMother )
1496 {
1497 ExitNormal = fGrandMotherExitNormal;
1498 *valid = true;
1499 fCalculatedExitNormal = true;
1500 }
1501 else // We are not at a boundary. ExitNormal remains (0,0,0)
1502 {
1503 *valid = false;
1504 fCalculatedExitNormal = false;
1505 G4ExceptionDescription message;
1506 message << "Function called when *NOT* at a Boundary." << G4endl;
1507 message << "Exit Normal not calculated." << G4endl;
1508 G4Exception("G4Navigator::GetLocalExitNormal()",
1509 "GeomNav0003", JustWarning, message);
1510 }
1511 }
1512 }
1513 return ExitNormal;
1514}
1515
1516// ********************************************************************
1517// GetMotherToDaughterTransform
1518//
1519// Obtains the mother to daughter affine transformation
1520// ********************************************************************
1521//
1524 G4int enteringReplicaNo,
1525 EVolume enteringVolumeType )
1526{
1527 switch (enteringVolumeType)
1528 {
1529 case kNormal: // Nothing is needed to prepare the transformation
1530 break; // It is stored already in the physical volume (placement)
1531 case kReplica: // Sets the transform in the Replica - tbc
1532 G4Exception("G4Navigator::GetMotherToDaughterTransform()",
1533 "GeomNav0001", FatalException,
1534 "Method NOT Implemented yet for replica volumes.");
1535 break;
1536 case kParameterised:
1537 if( pEnteringPhysVol->GetRegularStructureId() == 0 )
1538 {
1539 G4VPVParameterisation *pParam =
1540 pEnteringPhysVol->GetParameterisation();
1541 G4VSolid* pSolid =
1542 pParam->ComputeSolid(enteringReplicaNo, pEnteringPhysVol);
1543 pSolid->ComputeDimensions(pParam, enteringReplicaNo, pEnteringPhysVol);
1544
1545 // Sets the transform in the Parameterisation
1546 //
1547 pParam->ComputeTransformation(enteringReplicaNo, pEnteringPhysVol);
1548
1549 // Set the correct solid and material in Logical Volume
1550 //
1551 G4LogicalVolume* pLogical = pEnteringPhysVol->GetLogicalVolume();
1552 pLogical->SetSolid( pSolid );
1553 }
1554 break;
1555 case kExternal:
1556 // Expect that nothing is needed to prepare the transformation.
1557 // It is stored already in the physical volume (placement)
1558 break;
1559 }
1560 return G4AffineTransform(pEnteringPhysVol->GetRotation(),
1561 pEnteringPhysVol->GetTranslation()).Invert();
1562}
1563
1564
1565// ********************************************************************
1566// GetLocalExitNormalAndCheck
1567//
1568// Obtains the Normal vector to a surface (in local coordinates)
1569// pointing out of previous volume and into current volume, and
1570// checks the current point against expected 'local' value.
1571// ********************************************************************
1572//
1575#ifdef G4DEBUG_NAVIGATION
1576 const G4ThreeVector& ExpectedBoundaryPointGlobal,
1577#else
1578 const G4ThreeVector&,
1579#endif
1580 G4bool* pValid)
1581{
1582#ifdef G4DEBUG_NAVIGATION
1583 // Check Current point against expected 'local' value
1584 //
1585 if ( fLastTriedStepComputation )
1586 {
1587 G4ThreeVector ExpectedBoundaryPointLocal;
1588
1589 const G4AffineTransform& GlobalToLocal = GetGlobalToLocalTransform();
1590 ExpectedBoundaryPointLocal =
1591 GlobalToLocal.TransformPoint( ExpectedBoundaryPointGlobal );
1592
1593 // Add here: Comparison against expected position,
1594 // i.e. the endpoint of ComputeStep
1595 }
1596#endif
1597
1598 return GetLocalExitNormal( pValid );
1599}
1600
1601// ********************************************************************
1602// GetGlobalExitNormal
1603//
1604// Obtains the Normal vector to a surface (in global coordinates)
1605// pointing out of previous volume and into current volume
1606// ********************************************************************
1607//
1610 G4bool* pNormalCalculated)
1611{
1612 G4bool validNormal;
1613 G4ThreeVector localNormal, globalNormal;
1614
1615 G4bool usingStored = fCalculatedExitNormal && (
1616 ( fLastTriedStepComputation && fExiting ) // Just calculated it
1617 || // No locate in between
1618 ( !fLastTriedStepComputation
1619 && (IntersectPointGlobal-fStepEndPoint).mag2() < 10.0*fSqTol ) );
1620 // Calculated it 'just' before & then called locate
1621 // but it did not move position
1622
1623 if( usingStored )
1624 {
1625 // This was computed in last call to ComputeStep
1626 // and only if it arrived at boundary
1627 //
1628 globalNormal = fExitNormalGlobalFrame;
1629 G4double normMag2 = globalNormal.mag2();
1630 if( std::fabs ( normMag2 - 1.0 ) < perThousand ) // was perMillion
1631 {
1632 *pNormalCalculated = true; // ComputeStep always computes it if Exiting
1633 // (fExiting==true)
1634 }
1635 else
1636 {
1637 G4ExceptionDescription message;
1638 message.precision(10);
1639 message << " WARNING> Expected normal-global-frame to be valid, "
1640 << " i.e. a unit vector!" << G4endl
1641 << " - but |normal| = " << std::sqrt(normMag2)
1642 << " - and |normal|^2 = " << normMag2 << G4endl
1643 << " which differs from 1.0 by " << normMag2 - 1.0 << G4endl
1644 << " n = " << fExitNormalGlobalFrame << G4endl
1645 << " Global point: " << IntersectPointGlobal << G4endl
1646 << " Volume: " << fHistory.GetTopVolume()->GetName() << G4endl;
1647#ifdef G4VERBOSE
1648 G4LogicalVolume* candLog = fHistory.GetTopVolume()->GetLogicalVolume();
1649 if ( candLog != nullptr )
1650 {
1651 message << " Solid: " << candLog->GetSolid()->GetName()
1652 << ", Type: " << candLog->GetSolid()->GetEntityType() << G4endl
1653 << *candLog->GetSolid() << G4endl;
1654 }
1655#endif
1656 message << "============================================================"
1657 << G4endl;
1658 G4int oldVerbose = fVerbose;
1659 fVerbose = 4;
1660 message << " State of Navigator: " << G4endl;
1661 message << *this << G4endl;
1662 fVerbose = oldVerbose;
1663 message << "============================================================"
1664 << G4endl;
1665
1666 G4Exception("G4Navigator::GetGlobalExitNormal()",
1667 "GeomNav0003",JustWarning, message,
1668 "Value obtained from stored global-normal is not a unit vector.");
1669
1670 // (Re)Compute it now -- as either it was not computed, or it is wrong.
1671 //
1672 localNormal = GetLocalExitNormalAndCheck(IntersectPointGlobal,
1673 &validNormal);
1674 *pNormalCalculated = fCalculatedExitNormal;
1675 globalNormal = fHistory.GetTopTransform()
1676 .InverseTransformAxis(localNormal);
1677 }
1678 }
1679 else
1680 {
1681 localNormal = GetLocalExitNormalAndCheck(IntersectPointGlobal,&validNormal);
1682 *pNormalCalculated = fCalculatedExitNormal;
1683
1684#ifdef G4DEBUG_NAVIGATION
1685 usingStored = false;
1686
1687 if( (!validNormal) && !fCalculatedExitNormal )
1688 {
1690 edN << " Calculated = " << fCalculatedExitNormal << G4endl;
1691 edN << " Entering= " << fEntering << G4endl;
1692 G4int oldVerbose = this->GetVerboseLevel();
1693 this->SetVerboseLevel(4);
1694 edN << " State of Navigator: " << G4endl;
1695 edN << *this << G4endl;
1696 this->SetVerboseLevel( oldVerbose );
1697
1698 G4Exception("G4Navigator::GetGlobalExitNormal()",
1699 "GeomNav0003", JustWarning, edN,
1700 "LocalExitNormalAndCheck() did not calculate Normal.");
1701 }
1702#endif
1703
1704 G4double localMag2 = localNormal.mag2();
1705 if( validNormal && (std::fabs(localMag2-1.0)) > kToleranceNormalCheck )
1706 {
1708 edN.precision(10);
1709 edN << "G4Navigator::GetGlobalExitNormal: "
1710 << " Using Local Normal - from call to GetLocalExitNormalAndCheck. "
1711 << G4endl
1712 << " Local Exit Normal : " << " || = " << std::sqrt(localMag2)
1713 << " vec = " << localNormal << G4endl
1714 << " Global Exit Normal : " << " || = " << globalNormal.mag()
1715 << " vec = " << globalNormal << G4endl
1716 << " Global point: " << IntersectPointGlobal << G4endl;
1717 edN << " Calculated It = " << fCalculatedExitNormal << G4endl
1718 << " Volume: " << fHistory.GetTopVolume()->GetName() << G4endl;
1719#ifdef G4VERBOSE
1720 G4LogicalVolume* candLog = fHistory.GetTopVolume()->GetLogicalVolume();
1721 if ( candLog != nullptr )
1722 {
1723 edN << " Solid: " << candLog->GetSolid()->GetName()
1724 << ", Type: " << candLog->GetSolid()->GetEntityType() << G4endl
1725 << *candLog->GetSolid();
1726 }
1727#endif
1728 G4Exception("G4Navigator::GetGlobalExitNormal()",
1729 "GeomNav0003",JustWarning, edN,
1730 "Value obtained from new local *solid* is incorrect.");
1731 localNormal = localNormal.unit(); // Should we correct it ??
1732 }
1733 globalNormal = fHistory.GetTopTransform()
1734 .InverseTransformAxis(localNormal);
1735 }
1736
1737#ifdef G4DEBUG_NAVIGATION
1738 if( usingStored )
1739 {
1740 G4ThreeVector globalNormAgn;
1741
1742 localNormal = GetLocalExitNormalAndCheck(IntersectPointGlobal,&validNormal);
1743
1744 globalNormAgn = fHistory.GetTopTransform()
1745 .InverseTransformAxis(localNormal);
1746
1747 // Check the value computed against fExitNormalGlobalFrame
1748 G4ThreeVector diffNorm = globalNormAgn - fExitNormalGlobalFrame;
1749 if( diffNorm.mag2() > kToleranceNormalCheck )
1750 {
1752 edDfn << "Found difference in normals in case of exiting mother "
1753 << "- when Get is called after ComputingStep " << G4endl;
1754 edDfn << " Magnitude of diff = " << diffNorm.mag() << G4endl;
1755 edDfn << " Normal stored (Global) = " << fExitNormalGlobalFrame
1756 << G4endl;
1757 edDfn << " Global Computed from Local = " << globalNormAgn << G4endl;
1758 G4Exception("G4Navigator::GetGlobalExitNormal()", "GeomNav0003",
1759 JustWarning, edDfn);
1760 }
1761 }
1762#endif
1763
1764 // Synchronise stored global exit normal as possibly re-computed here
1765 //
1766 fExitNormalGlobalFrame = globalNormal;
1767
1768 return globalNormal;
1769}
1770
1771// ********************************************************************
1772// ComputeSafety
1773//
1774// It assumes that it will be
1775// i) called at the Point in the same volume as the EndPoint of the
1776// ComputeStep.
1777// ii) after (or at the end of) ComputeStep OR after the relocation.
1778// ********************************************************************
1779//
1781 const G4double pMaxLength,
1782 const G4bool )
1783{
1784 G4VPhysicalVolume *motherPhysical = fHistory.GetTopVolume();
1785 G4double safety = 0.0;
1786
1787 G4double distEndpointSq = (pGlobalpoint-fStepEndPoint).mag2();
1788 G4bool stayedOnEndpoint = distEndpointSq < sqr(kCarTolerance);
1789 G4bool endpointOnSurface = fEnteredDaughter || fExitedMother;
1790
1791 G4bool onSurface = endpointOnSurface && stayedOnEndpoint;
1792 if( ! onSurface )
1793 {
1794 safety= fpSafetyCalculator->SafetyInCurrentVolume(pGlobalpoint, motherPhysical, pMaxLength);
1795 // offload to G4SafetyCalculator - avoids need to save / reload state
1796
1797 // Remember last safety origin & value
1798 //
1799 fPreviousSftOrigin = pGlobalpoint;
1800 fPreviousSafety = safety;
1801 // We overwrite the Safety 'sphere' - keeping old behaviour
1802 }
1803
1804 return safety;
1805}
1806
1807// ********************************************************************
1808// CreateTouchableHistoryHandle
1809// ********************************************************************
1810//
1815
1816// ********************************************************************
1817// PrintState
1818// ********************************************************************
1819//
1821{
1822 G4long oldcoutPrec = G4cout.precision(4);
1823 if( fVerbose >= 4 )
1824 {
1825 G4cout << "The current state of G4Navigator is: " << G4endl;
1826 G4cout << " ValidExitNormal= " << fValidExitNormal // << G4endl
1827 << " ExitNormal = " << fExitNormal // << G4endl
1828 << " Exiting = " << fExiting // << G4endl
1829 << " Entering = " << fEntering // << G4endl
1830 << " BlockedPhysicalVolume= " ;
1831 if (fBlockedPhysicalVolume==nullptr)
1832 {
1833 G4cout << "None";
1834 }
1835 else
1836 {
1837 G4cout << fBlockedPhysicalVolume->GetName();
1838 }
1839 G4cout << G4endl
1840 << " BlockedReplicaNo = " << fBlockedReplicaNo // << G4endl
1841 << " LastStepWasZero = " << fLastStepWasZero // << G4endl
1842 << G4endl;
1843 }
1844 if( ( 1 < fVerbose) && (fVerbose < 4) )
1845 {
1846 G4cout << G4endl; // Make sure to line up
1847 G4cout << std::setw(30) << " ExitNormal " << " "
1848 << std::setw( 5) << " Valid " << " "
1849 << std::setw( 9) << " Exiting " << " "
1850 << std::setw( 9) << " Entering" << " "
1851 << std::setw(15) << " Blocked:Volume " << " "
1852 << std::setw( 9) << " ReplicaNo" << " "
1853 << std::setw( 8) << " LastStepZero " << " "
1854 << G4endl;
1855 G4cout << "( " << std::setw(7) << fExitNormal.x()
1856 << ", " << std::setw(7) << fExitNormal.y()
1857 << ", " << std::setw(7) << fExitNormal.z() << " ) "
1858 << std::setw( 5) << fValidExitNormal << " "
1859 << std::setw( 9) << fExiting << " "
1860 << std::setw( 9) << fEntering << " ";
1861 if ( fBlockedPhysicalVolume == nullptr )
1862 { G4cout << std::setw(15) << "None"; }
1863 else
1864 { G4cout << std::setw(15)<< fBlockedPhysicalVolume->GetName(); }
1865 G4cout << std::setw( 9) << fBlockedReplicaNo << " "
1866 << std::setw( 8) << fLastStepWasZero << " "
1867 << G4endl;
1868 }
1869 if( fVerbose > 2 )
1870 {
1871 G4cout.precision(8);
1872 G4cout << " Current Localpoint = " << fLastLocatedPointLocal << G4endl;
1873 G4cout << " PreviousSftOrigin = " << fPreviousSftOrigin << G4endl;
1874 G4cout << " PreviousSafety = " << fPreviousSafety << G4endl;
1875 }
1876 G4cout.precision(oldcoutPrec);
1877}
1878
1879// ********************************************************************
1880// ComputeStepLog
1881// ********************************************************************
1882//
1883void G4Navigator::ComputeStepLog(const G4ThreeVector& pGlobalpoint,
1884 G4double moveLenSq) const
1885{
1886 // The following checks only make sense if the move is larger
1887 // than the tolerance.
1888
1889 const G4double fAccuracyForWarning = kCarTolerance,
1890 fAccuracyForException = 1000*kCarTolerance;
1891
1892 G4ThreeVector OriginalGlobalpoint = fHistory.GetTopTransform().
1893 InverseTransformPoint(fLastLocatedPointLocal);
1894
1895 G4double shiftOriginSafSq = (fPreviousSftOrigin-pGlobalpoint).mag2();
1896
1897 // Check that the starting point of this step is
1898 // within the isotropic safety sphere of the last point
1899 // to a accuracy/precision given by fAccuracyForWarning.
1900 // If so give warning.
1901 // If it fails by more than fAccuracyForException exit with error.
1902 //
1903 if( shiftOriginSafSq >= sqr(fPreviousSafety) )
1904 {
1905 G4double shiftOrigin = std::sqrt(shiftOriginSafSq);
1906 G4double diffShiftSaf = shiftOrigin - fPreviousSafety;
1907
1908 if( diffShiftSaf > fAccuracyForWarning )
1909 {
1910 G4long oldcoutPrec = G4cout.precision(8);
1911 G4long oldcerrPrec = G4cerr.precision(10);
1912 std::ostringstream message, suggestion;
1913 message << "Accuracy error or slightly inaccurate position shift."
1914 << G4endl
1915 << " The Step's starting point has moved "
1916 << std::sqrt(moveLenSq)/mm << " mm " << G4endl
1917 << " since the last call to a Locate method." << G4endl
1918 << " This has resulted in moving "
1919 << shiftOrigin/mm << " mm "
1920 << " from the last point at which the safety "
1921 << " was calculated " << G4endl
1922 << " which is more than the computed safety= "
1923 << fPreviousSafety/mm << " mm at that point." << G4endl
1924 << " This difference is "
1925 << diffShiftSaf/mm << " mm." << G4endl
1926 << " The tolerated accuracy is "
1927 << fAccuracyForException/mm << " mm.";
1928
1929 suggestion << " ";
1930 static G4ThreadLocal G4int warnNow = 0;
1931 if( ((++warnNow % 100) == 1) )
1932 {
1933 message << G4endl
1934 << " This problem can be due to either " << G4endl
1935 << " - a process that has proposed a displacement"
1936 << " larger than the current safety , or" << G4endl
1937 << " - inaccuracy in the computation of the safety";
1938 suggestion << "We suggest that you " << G4endl
1939 << " - find i) what particle is being tracked, and "
1940 << " ii) through what part of your geometry " << G4endl
1941 << " for example by re-running this event with "
1942 << G4endl
1943 << " /tracking/verbose 1 " << G4endl
1944 << " - check which processes you declare for"
1945 << " this particle (and look at non-standard ones)"
1946 << G4endl
1947 << " - in case, create a detailed logfile"
1948 << " of this event using:" << G4endl
1949 << " /tracking/verbose 6 ";
1950 }
1951 G4Exception("G4Navigator::ComputeStep()",
1952 "GeomNav1002", JustWarning,
1953 message, G4String(suggestion.str()));
1954 G4cout.precision(oldcoutPrec);
1955 G4cerr.precision(oldcerrPrec);
1956 }
1957#ifdef G4DEBUG_NAVIGATION
1958 else
1959 {
1960 G4cerr << "WARNING - G4Navigator::ComputeStep()" << G4endl
1961 << " The Step's starting point has moved "
1962 << std::sqrt(moveLenSq) << "," << G4endl
1963 << " which has taken it to the limit of"
1964 << " the current safety. " << G4endl;
1965 }
1966#endif
1967 }
1968 G4double safetyPlus = fPreviousSafety + fAccuracyForException;
1969 if ( shiftOriginSafSq > sqr(safetyPlus) )
1970 {
1971 std::ostringstream message;
1972 message << "May lead to a crash or unreliable results." << G4endl
1973 << " Position has shifted considerably without"
1974 << " notifying the navigator !" << G4endl
1975 << " Tolerated safety: " << safetyPlus << G4endl
1976 << " Computed shift : " << shiftOriginSafSq;
1977 G4Exception("G4Navigator::ComputeStep()", "GeomNav1002",
1978 JustWarning, message);
1979 }
1980}
1981
1982// ********************************************************************
1983// CheckOverlapsIterative
1984// ********************************************************************
1985//
1987{
1988 // Check and report overlaps
1989 //
1990 G4bool foundOverlap = false;
1991 G4int nPoints = 300000, ntrials = 9, numOverlaps = 5;
1992 G4double trialLength = 1.0 * CLHEP::centimeter;
1993 while ( ntrials-- > 0 && !foundOverlap )
1994 {
1995 if ( fVerbose > 1 )
1996 {
1997 G4cout << " ** Running overlap checks in volume "
1998 << vol->GetName()
1999 << " with length = " << trialLength << G4endl;
2000 }
2001 foundOverlap = vol->CheckOverlaps(nPoints, trialLength,
2002 fVerbose != 0, numOverlaps);
2003 trialLength *= 0.1;
2004 if ( trialLength <= 1.0e-5 ) { numOverlaps= 1;}
2005 }
2006 return foundOverlap;
2007}
2008
2009// ********************************************************************
2010// Operator <<
2011// ********************************************************************
2012//
2013std::ostream& operator << (std::ostream &os,const G4Navigator &n)
2014{
2015 // Old version did only the following:
2016 // os << "Current History: " << G4endl << n.fHistory;
2017 // Old behaviour is recovered for fVerbose = 0
2018
2019 // Adapted from G4Navigator::PrintState() const
2020
2021 G4long oldcoutPrec = os.precision(4);
2022 if( n.fVerbose >= 4 )
2023 {
2024 os << "The current state of G4Navigator is: " << G4endl;
2025 os << " ValidExitNormal= " << n.fValidExitNormal << G4endl
2026 << " ExitNormal = " << n.fExitNormal << G4endl
2027 << " Exiting = " << n.fExiting << G4endl
2028 << " Entering = " << n.fEntering << G4endl
2029 << " BlockedPhysicalVolume= " ;
2030 if (n.fBlockedPhysicalVolume==nullptr)
2031 {
2032 os << "None";
2033 }
2034 else
2035 {
2036 os << n.fBlockedPhysicalVolume->GetName();
2037 }
2038 os << G4endl
2039 << " BlockedReplicaNo = " << n.fBlockedReplicaNo << G4endl
2040 << " LastStepWasZero = " << n.fLastStepWasZero << G4endl
2041 << G4endl;
2042 }
2043 if( ( 1 < n.fVerbose) && (n.fVerbose < 4) )
2044 {
2045 os << G4endl; // Make sure to line up
2046 os << std::setw(30) << " ExitNormal " << " "
2047 << std::setw( 5) << " Valid " << " "
2048 << std::setw( 9) << " Exiting " << " "
2049 << std::setw( 9) << " Entering" << " "
2050 << std::setw(15) << " Blocked:Volume " << " "
2051 << std::setw( 9) << " ReplicaNo" << " "
2052 << std::setw( 8) << " LastStepZero " << " "
2053 << G4endl;
2054 os << "( " << std::setw(7) << n.fExitNormal.x()
2055 << ", " << std::setw(7) << n.fExitNormal.y()
2056 << ", " << std::setw(7) << n.fExitNormal.z() << " ) "
2057 << std::setw( 5) << n.fValidExitNormal << " "
2058 << std::setw( 9) << n.fExiting << " "
2059 << std::setw( 9) << n.fEntering << " ";
2060 if ( n.fBlockedPhysicalVolume==nullptr )
2061 { os << std::setw(15) << "None"; }
2062 else
2063 { os << std::setw(15)<< n.fBlockedPhysicalVolume->GetName(); }
2064 os << std::setw( 9) << n.fBlockedReplicaNo << " "
2065 << std::setw( 8) << n.fLastStepWasZero << " "
2066 << G4endl;
2067 }
2068 if( n.fVerbose > 2 )
2069 {
2070 os.precision(8);
2071 os << " Current Localpoint = " << n.fLastLocatedPointLocal << G4endl;
2072 os << " PreviousSftOrigin = " << n.fPreviousSftOrigin << G4endl;
2073 os << " PreviousSafety = " << n.fPreviousSafety << G4endl;
2074 }
2075 if( n.fVerbose > 3 || n.fVerbose == 0 )
2076 {
2077 os << "Current History: " << G4endl << n.fHistory;
2078 }
2079
2080 os.precision(oldcoutPrec);
2081 return os;
2082}
2083
2084// ********************************************************************
2085// SetVoxelNavigation: alternative navigator for voxelised geometry
2086// ********************************************************************
2087//
2089{
2090 delete fpvoxelNav;
2091 fpvoxelNav = voxelNav;
2092}
2093
2094// ********************************************************************
2095// InformLastStep: derived navigators can inform of its step
2096// used to update fLastStepWasZero
2097// ********************************************************************
2098void G4Navigator::InformLastStep(G4double lastStep, G4bool entersDaughtVol,
2099 G4bool exitsMotherVol)
2100{
2101 G4bool zeroStep = ( lastStep == 0.0 );
2102 fLocatedOnEdge = fLastStepWasZero && zeroStep;
2103 fLastStepWasZero = zeroStep;
2104
2105 fExiting = exitsMotherVol;
2106 fEntering = entersDaughtVol;
2107}
2108
2109// ********************************************************************
2110// SetExternalNavigation
2111// ********************************************************************
2112//
2114{
2115 fpExternalNav = externalNav;
2116 fpSafetyCalculator->SetExternalNavigation(externalNav);
2117}
const G4double kCarTolerance
@ JustWarning
@ FatalException
@ EventMustBeAborted
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
std::ostringstream G4ExceptionDescription
#define G4DEBUG_NAVIGATION
#define fHistory
#define fLastLocatedPointLocal
#define fPreviousSftOrigin
#define fPreviousSafety
std::ostream & operator<<(std::ostream &os, const G4Navigator &n)
EVolume VolumeType() const override
CLHEP::HepRotation G4RotationMatrix
CLHEP::Hep3Vector G4ThreeVector
G4ReferenceCountedHandle< G4VTouchable > G4TouchableHandle
G4TouchableHandle is a type providing reference counting mechanism for any kind of touchable objects....
double G4double
Definition G4Types.hh:83
long G4long
Definition G4Types.hh:87
bool G4bool
Definition G4Types.hh:86
int G4int
Definition G4Types.hh:85
G4GLOB_DLL std::ostream G4cerr
#define G4endl
Definition G4ios.hh:67
G4GLOB_DLL std::ostream G4cout
Hep3Vector unit() const
double mag2() const
double dot(const Hep3Vector &) const
double mag() const
G4AffineTransform is a class for geometric affine transformations. It supports efficient arbitrary ro...
G4ThreeVector InverseTransformAxis(const G4ThreeVector &axis) const
G4AffineTransform & Invert()
G4ThreeVector TransformPoint(const G4ThreeVector &vec) const
G4double GetSurfaceTolerance() const
static G4GeometryTolerance * GetInstance()
G4LogicalVolume represents a leaf node or unpositioned subtree in the geometry hierarchy....
G4VSolid * GetSolid() const
const G4String & GetName() const
void SetSolid(G4VSolid *pSolid)
G4SmartVoxelHeader * GetVoxelHeader() const
void UpdateMaterial(G4Material *pMaterial)
G4double fMinStep
void RestoreSavedState()
void SetVerboseLevel(G4int level)
virtual void SetupHierarchy()
G4TouchableHistory * CreateTouchableHistory() const
G4ThreeVector fStepEndPoint
void SetExternalNavigation(G4VExternalNavigation *externalNav)
G4int GetVerboseLevel() const
G4bool fExitedMother
virtual void ResetState()
G4bool fEnteredDaughter
virtual G4double ComputeSafety(const G4ThreeVector &globalpoint, const G4double pProposedMaxLength=DBL_MAX, const G4bool keepState=true)
G4ThreeVector ComputeLocalPoint(const G4ThreeVector &rGlobP) const
virtual void LocateGlobalPointWithinVolume(const G4ThreeVector &position)
G4ThreeVector fLastStepEndPointLocal
G4bool fWasLimitedByGeometry
G4VoxelNavigation & GetVoxelNavigator()
virtual ~G4Navigator()
G4double fSqTol
G4bool CheckOverlapsIterative(G4VPhysicalVolume *vol)
void SetSavedState()
EVolume CharacteriseDaughters(const G4LogicalVolume *pLog) const
virtual G4ThreeVector GetGlobalExitNormal(const G4ThreeVector &point, G4bool *valid)
void SetVoxelNavigation(G4VoxelNavigation *voxelNav)
void PrintState() const
G4ThreeVector ComputeLocalAxis(const G4ThreeVector &pVec) const
G4double kCarTolerance
virtual G4ThreeVector GetLocalExitNormalAndCheck(const G4ThreeVector &point, G4bool *valid)
virtual G4ThreeVector GetLocalExitNormal(G4bool *valid)
void InformLastStep(G4double lastStep, G4bool entersDaughtVol, G4bool exitsMotherVol)
virtual G4double ComputeStep(const G4ThreeVector &pGlobalPoint, const G4ThreeVector &pDirection, const G4double pCurrentProposedStepLength, G4double &pNewSafety)
virtual G4VPhysicalVolume * LocateGlobalPointAndSetup(const G4ThreeVector &point, const G4ThreeVector *direction=nullptr, const G4bool pRelativeSearch=true, const G4bool ignoreDirection=true)
G4AffineTransform GetMotherToDaughterTransform(G4VPhysicalVolume *dVolume, G4int dReplicaNo, EVolume dVolumeType)
void ResetStackAndState()
G4bool EnteredDaughterVolume() const
G4double CheckNextStep(const G4ThreeVector &pGlobalPoint, const G4ThreeVector &pDirection, const G4double pCurrentProposedStepLength, G4double &pNewSafety)
virtual G4VPhysicalVolume * ResetHierarchyAndLocate(const G4ThreeVector &point, const G4ThreeVector &direction, const G4TouchableHistory &h)
G4int GetDaughtersRegularStructureId(const G4LogicalVolume *pLv) const
G4NavigationHistory fHistory
virtual G4TouchableHandle CreateTouchableHistoryHandle() const
const G4AffineTransform & GetGlobalToLocalTransform() const
G4SafetyCalculator is a class that provides an estimate of the isotropic safety (the minimum distance...
G4TouchableHistory is an object representing a touchable detector element, and its history in the geo...
const G4NavigationHistory * GetHistory() const
G4int MoveUpHistory(G4int num_levels=1)
G4VExternalNavigation is a pure virtual class to be specialised by the user for tracking with an exte...
G4VPVParameterisation ia an abstract base class for Parameterisation, able to compute the transformat...
virtual void ComputeTransformation(const G4int no, G4VPhysicalVolume *pv) const =0
virtual G4VSolid * ComputeSolid(const G4int no, G4VPhysicalVolume *pv)
virtual G4bool IsNested() const
G4VPhysicalVolume is an abstract base class for the representation of a positioned volume....
const G4RotationMatrix * GetRotation() const
const G4ThreeVector GetTranslation() const
virtual G4bool CheckOverlaps(G4int res=1000, G4double tol=0., G4bool verbose=true, G4int errMax=1)
G4LogicalVolume * GetLogicalVolume() const
virtual G4int GetCopyNo() const =0
const G4String & GetName() const
virtual G4int GetRegularStructureId() const =0
virtual G4VPVParameterisation * GetParameterisation() const =0
G4VSolid is an abstract base class for solids, physical shapes that can be tracked through....
Definition G4VSolid.hh:80
G4String GetName() const
virtual EInside Inside(const G4ThreeVector &p) const =0
virtual void ComputeDimensions(G4VPVParameterisation *p, const G4int n, const G4VPhysicalVolume *pRep)
Definition G4VSolid.cc:136
virtual G4double DistanceToOut(const G4ThreeVector &p, const G4ThreeVector &v, const G4bool calcNorm=false, G4bool *validNorm=nullptr, G4ThreeVector *n=nullptr) const =0
virtual G4ThreeVector SurfaceNormal(const G4ThreeVector &p) const =0
virtual G4double DistanceToIn(const G4ThreeVector &p, const G4ThreeVector &v) const =0
virtual G4GeometryType GetEntityType() const =0
G4VoxelNavigation is a concrete utility class for navigation in volumes containing only G4PVPlacement...
G4double ComputeStep(const G4ThreeVector &localPoint, const G4ThreeVector &localDirection, const G4double currentProposedStepLength, G4double &newSafety, G4NavigationHistory &history, G4bool &validExitNormal, G4ThreeVector &exitNormal, G4bool &exiting, G4bool &entering, G4VPhysicalVolume *(*pBlockedPhysical), G4int &blockedReplicaNo) override
void RelocateWithinVolume(G4VPhysicalVolume *motherPhysical, const G4ThreeVector &localPoint) override
G4bool LevelLocate(G4NavigationHistory &history, const G4VPhysicalVolume *blockedVol, const G4int blockedNum, const G4ThreeVector &globalPoint, const G4ThreeVector *globalDirection, const G4bool pLocatedOnEdge, G4ThreeVector &localPoint) override
G4VoxelSafety is an utility class for the handling isotropic safety in volumes containing only G4PVPl...
EInside
Definition geomdefs.hh:67
@ kInside
Definition geomdefs.hh:70
@ kOutside
Definition geomdefs.hh:68
@ kSurface
Definition geomdefs.hh:69
EVolume
Definition geomdefs.hh:83
@ kNormal
Definition geomdefs.hh:84
@ kParameterised
Definition geomdefs.hh:86
@ kExternal
Definition geomdefs.hh:87
@ kReplica
Definition geomdefs.hh:85
T sqr(const T &x)
Definition templates.hh:128
#define G4ThreadLocal
Definition tls.hh:77