ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4CoupledTransportation.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file G4CoupledTransportation.cc
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 //
27 //
28 // ------------------------------------------------------------
29 // GEANT 4 class implementation
30 //
31 // =======================================================================
32 // Created: 19 March 1997, J. Apostolakis
33 // =======================================================================
34 
38 
39 #include "G4PhysicalConstants.hh"
40 #include "G4SystemOfUnits.hh"
41 #include "G4ProductionCutsTable.hh"
42 #include "G4ParticleTable.hh"
43 #include "G4ChordFinder.hh"
44 #include "G4Field.hh"
45 #include "G4FieldTrack.hh"
46 #include "G4FieldManagerStore.hh"
47 
48 #include "G4Transportation.hh" // In order to use fUseMagneticMoment
49 
51 
53 // This mode must apply to all threads
54 
59 //
60 // Constructor
61 
63  : G4VProcess( G4String("CoupledTransportation"), fTransportation ),
64  fTransportEndPosition(0.0, 0.0, 0.0),
65  fTransportEndMomentumDir(0.0, 0.0, 0.0),
66  fTransportEndKineticEnergy(0.0),
67  fTransportEndSpin(0.0, 0.0, 0.0),
68  fMomentumChanged(false),
69  fEndGlobalTimeComputed(false),
70  fCandidateEndGlobalTime(0.0),
71  fParticleIsLooping( false ),
72  fNewTrack( true ),
73  fPreviousSftOrigin( 0.,0.,0. ),
74  fPreviousMassSafety( 0.0 ),
75  fPreviousFullSafety( 0.0 ),
76  fMassGeometryLimitedStep( false ),
77  fAnyGeometryLimitedStep( false ),
78  fEndpointDistance( -1.0 ),
79  fSumEnergyKilled( 0.0 ), fMaxEnergyKilled( 0.0 ),
80  fFirstStepInMassVolume( true ),
81  fFirstStepInAnyVolume( true )
82 {
83  SetProcessSubType(static_cast<G4int>(COUPLED_TRANSPORTATION));
84  SetVerboseLevel(verbosity);
85 
86  G4TransportationManager* transportMgr ;
87 
89 
90  fMassNavigator = transportMgr->GetNavigatorForTracking() ;
91  fFieldPropagator = transportMgr->GetPropagatorInField() ;
92  // fGlobalFieldMgr = transportMgr->GetFieldManager() ;
94  if( verboseLevel > 0 )
95  {
96  G4cout << " G4CoupledTransportation constructor: ----- " << G4endl;
97  G4cout << " Verbose level is " << verboseLevel << G4endl;
98  G4cout << " Navigator Id obtained in G4CoupledTransportation constructor "
99  << fNavigatorId << G4endl;
100  G4cout << " Reports First/Last in "
101  << (fSignifyStepInAnyVolume ? " any " : " mass " )
102  << " geometry " << G4endl;
103  }
105  fpSafetyHelper = transportMgr->GetSafetyHelper(); // New
106 
107  fpLogger = new G4TransportationLogger("G4Transportation", verbosity);
108 
110  // Use the old defaults: Warning = 100 MeV, Important = 250 MeV, No Trials = 10;
111 
113  // Should be done by Set methods in SetHighLooperThresholds -- making sure
114 
115  static G4ThreadLocal G4TouchableHandle* pNullTouchableHandle = 0;
116  if ( !pNullTouchableHandle) { pNullTouchableHandle = new G4TouchableHandle; }
117  fCurrentTouchableHandle = *pNullTouchableHandle;
118  // Points to (G4VTouchable*) 0
119 
121 }
122 
124 
126 {
127  if( fSumEnergyKilled > 0.0 )
128  {
130  }
131  delete fpLogger;
132 }
133 
135 
136 void
137 G4CoupledTransportation::PrintStatistics( std::ostream& outStr) const
138 {
139  if( fSumEnergyKilled > 0.0 )
140  {
141  outStr << " G4CoupledTransportation: Statistics for looping particles "
142  << G4endl;
143  outStr << " Sum of energy of loopers killed: "
144  << fSumEnergyKilled / MeV << " MeV " << G4endl;
145  outStr << " Max energy of loopers killed: "
146  << fMaxEnergyKilled / MeV << " MeV " << G4endl;
147 
148 
149  outStr << " Max energy of loopers 'saved': " << fMaxEnergySaved << G4endl;
150  outStr << " Sum of energy of loopers 'saved': "
151  << fSumEnergySaved << G4endl;
152  outStr << " Sum of energy of unstable loopers 'saved': "
154  }
155 }
156 
158 //
159 // Responsibilities:
160 // Find whether the geometry limits the Step, and to what length
161 // Calculate the new value of the safety and return it.
162 // Store the final time, position and momentum.
163 
166  G4double, // previousStepSize
167  G4double currentMinimumStep,
168  G4double& proposedSafetyForStart,
169  G4GPILSelection* selection )
170 {
171  G4double geometryStepLength;
172  G4double startMassSafety= 0.0; // estimated safety for start point (mass geometry)
173  G4double startFullSafety= 0.0; // estimated safety for start point (all geometries)
174  G4double safetyProposal= -1.0; // local copy of proposal
175 
176  G4ThreeVector EndUnitMomentum ;
177  G4double lengthAlongCurve = 0.0 ;
178 
180 
181  // Initial actions moved to StartTrack()
182  // --------------------------------------
183  // Note: in case another process changes touchable handle
184  // it will be necessary to add here (for all steps)
185  // fCurrentTouchableHandle = aTrack->GetTouchableHandle();
186 
187  // GPILSelection is set to defaule value of CandidateForSelection
188  // It is a return value
189  //
190  *selection = CandidateForSelection ;
191 
194 
195 #ifdef G4DEBUG_TRANSPORT
196  G4cout << " CoupledTransport::AlongStep GPIL: "
197  << " 1st-step: any= " <<fFirstStepInAnyVolume << " ( geom= "
198  << fAnyGeometryLimitedStep << " ) "
199  << " mass= " << fFirstStepInMassVolume << " ( geom= "
200  << fMassGeometryLimitedStep << " ) "
201  << " newTrack= " << fNewTrack << G4endl;
202 #endif
203 
204  // fLastStepInVolume= false;
205  fNewTrack = false;
206 
207  // Get initial Energy/Momentum of the track
208  //
209  const G4DynamicParticle* pParticle = track.GetDynamicParticle() ;
210  const G4ParticleDefinition* pParticleDef = pParticle->GetDefinition() ;
211  G4ThreeVector startMomentumDir = pParticle->GetMomentumDirection() ;
212  G4ThreeVector startPosition = track.GetPosition() ;
213  G4VPhysicalVolume* currentVolume= track.GetVolume();
214 
215 #ifdef G4DEBUG_TRANSPORT
216  if( verboseLevel > 1 )
217  {
218  G4cout << "G4CoupledTransportation::AlongStepGPIL> called in volume "
219  << currentVolume->GetName() << G4endl;
220  }
221 #endif
222  // G4double theTime = track.GetGlobalTime() ;
223 
224  // The Step Point safety can be limited by other geometries and/or the
225  // assumptions of any process - it's not always the geometrical safety.
226  // We calculate the starting point's isotropic safety here.
227  //
228  G4ThreeVector OriginShift = startPosition - fPreviousSftOrigin ;
229  G4double MagSqShift = OriginShift.mag2() ;
230  startMassSafety = 0.0;
231  startFullSafety= 0.0;
232 
233  // Recall that FullSafety <= MassSafety
234  // Original: if( MagSqShift < sqr(fPreviousMassSafety) ) {
235  if( MagSqShift < sqr(fPreviousFullSafety) )
236  {
237  G4double mag_shift= std::sqrt(MagSqShift);
238  startMassSafety = std::max( (fPreviousMassSafety - mag_shift), 0.0);
239  startFullSafety = std::max( (fPreviousFullSafety - mag_shift), 0.0);
240  // Need to be consistent between full safety with Mass safety
241  // in order reproduce results in simple case
242  // --> use same calculation method
243 
244  // Only compute full safety if massSafety > 0. Else it remains 0
245  // startFullSafety = fPathFinder->ComputeSafety( startPosition );
246  }
247 
248  // Is the particle charged or has it a magnetic moment?
249  //
250  G4double particleCharge = pParticle->GetCharge() ;
251  G4double magneticMoment = pParticle->GetMagneticMoment() ;
252  G4double restMass = pParticle->GetMass() ;
253 
254  fMassGeometryLimitedStep = false ; // Set default - alex
255  fAnyGeometryLimitedStep = false;
256 
257  // There is no need to locate the current volume. It is Done elsewhere:
258  // On track construction
259  // By the tracking, after all AlongStepDoIts, in "Relocation"
260 
261  // Check if the particle has a force, EM or gravitational, exerted on it
262  //
263  G4FieldManager* fieldMgr= nullptr;
264  G4bool fieldExertsForce = false ;
265 
266  const G4Field* ptrField= nullptr;
267 
268  fieldMgr = fFieldPropagator->FindAndSetFieldManager( track.GetVolume() );
269  G4bool eligibleEM = (particleCharge != 0.0)
270  || ( fUseMagneticMoment && (magneticMoment != 0.0) );
271  G4bool eligibleGrav = fUseGravity && (restMass != 0.0) ;
272 
273  if( (fieldMgr!=nullptr) && (eligibleEM||eligibleGrav) )
274  {
275  // Message the field Manager, to configure it for this track
276  //
277  fieldMgr->ConfigureForTrack( &track );
278 
279  // The above call can transition from a null field-ptr oto a finite field.
280  // If the field manager has no field ptr, the field is zero
281  // by definition ( = there is no field ! )
282  //
283  ptrField= fieldMgr->GetDetectorField();
284 
285  if( ptrField != nullptr)
286  {
287  fieldExertsForce = eligibleEM
288  || ( eligibleGrav && ptrField->IsGravityActive() );
289  }
290  }
291  G4double momentumMagnitude = pParticle->GetTotalMomentum() ;
292 
293  if( fieldExertsForce )
294  {
295  auto equationOfMotion= fFieldPropagator->GetCurrentEquationOfMotion();
296 
297  G4ChargeState chargeState(particleCharge, // Charge can change (dynamic)
298  magneticMoment,
299  pParticleDef->GetPDGSpin() );
300  if( equationOfMotion )
301  {
302  equationOfMotion->SetChargeMomentumMass( chargeState,
303  momentumMagnitude,
304  restMass );
305  }
306 #ifdef G4DEBUG_TRANSPORT
307  else
308  {
309  G4cerr << " ERROR in G4CoupledTransportation> "
310  << "Cannot find valid Equation of motion: " << G4endl;
311  << " Unable to pass Charge, Momentum and Mass " << G4endl;
312  }
313 #endif
314  }
315 
316  G4ThreeVector polarizationVec = track.GetPolarization() ;
317  G4FieldTrack aFieldTrack = G4FieldTrack(startPosition,
318  track.GetGlobalTime(), // Lab.
319  track.GetMomentumDirection(),
320  track.GetKineticEnergy(),
321  restMass,
322  particleCharge,
323  polarizationVec,
324  pParticleDef->GetPDGMagneticMoment(),
325  0.0, // Length along track
326  pParticleDef->GetPDGSpin() ) ;
327  G4int stepNo= track.GetCurrentStepNumber();
328 
329  ELimited limitedStep;
330  G4FieldTrack endTrackState('a'); // Default values
331 
332  fMassGeometryLimitedStep = false ; // default
334  if( currentMinimumStep > 0 )
335  {
336  G4double newMassSafety= 0.0; // temp. for recalculation
337 
338  // Do the Transport in the field (non recti-linear)
339  //
340  lengthAlongCurve = fPathFinder->ComputeStep( aFieldTrack,
341  currentMinimumStep,
342  fNavigatorId,
343  stepNo,
344  newMassSafety,
345  limitedStep,
346  endTrackState,
347  currentVolume ) ;
348 
349  G4double newFullSafety= fPathFinder->GetCurrentSafety();
350  // this was estimated already in step above
351 
352  if( limitedStep == kUnique || limitedStep == kSharedTransport )
353  {
355  }
356 
358 
359 #ifdef G4DEBUG_TRANSPORT
361  {
362  std::ostringstream message;
363  message << " ERROR in determining geometries limiting the step" << G4endl;
364  message << " Limiting: mass=" << fMassGeometryLimitedStep
365  << " any= " << fAnyGeometryLimitedStep << G4endl;
366  message << "Incompatible conditions - by which geometries was it limited ?";
367  G4Exception("G4CoupledTransportation::AlongStepGetPhysicalInteractionLength()",
368  "PathFinderConfused", FatalException, message);
369  }
370 #endif
371 
372  geometryStepLength = std::min( lengthAlongCurve, currentMinimumStep);
373 
374  // Momentum: Magnitude and direction can be changed too now ...
375  //
377  fTransportEndMomentumDir = endTrackState.GetMomentumDir() ;
378 
379  // Remember last safety origin & value.
380  fPreviousSftOrigin = startPosition ;
381  fPreviousMassSafety = newMassSafety ;
382  fPreviousFullSafety = newFullSafety ;
383  // fpSafetyHelper->SetCurrentSafety( newFullSafety, startPosition);
384 
385 #ifdef G4DEBUG_TRANSPORT
386  if( verboseLevel > 1 )
387  {
388  G4cout << "G4Transport:CompStep> "
389  << " called the pathfinder for a new step at " << startPosition
390  << " and obtained step = " << lengthAlongCurve << G4endl;
391  G4cout << " New safety (preStep) = " << newMassSafety
392  << " versus precalculated = " << startMassSafety << G4endl;
393  }
394 #endif
395 
396  // Store as best estimate value
397  startMassSafety = newMassSafety ;
398  startFullSafety = newFullSafety ;
399 
400  // Get the End-Position and End-Momentum (Dir-ection)
401  fTransportEndPosition = endTrackState.GetPosition() ;
402  fTransportEndKineticEnergy = endTrackState.GetKineticEnergy() ;
403  }
404  else
405  {
406  geometryStepLength = lengthAlongCurve= 0.0 ;
408  // fMassGeometryLimitedStep = false ; // --- ???
409  // fAnyGeometryLimitedStep = true;
412 
413  fTransportEndPosition = startPosition;
414 
415  endTrackState= aFieldTrack; // Ensures that time is updated
416 
417  // If the step length requested is 0, and we are on a boundary
418  // then a boundary will also limit the step.
419  if( startMassSafety == 0.0 )
420  {
423  }
424  // TODO: Add explicit logical status for being at a boundary
425  }
426  // G4FieldTrack aTrackState(endTrackState);
427 
428  if( !fieldExertsForce )
429  {
433  }
434  else
435  {
437 
438 #ifdef G4DEBUG_TRANSPORT
439  if( verboseLevel > 1 )
440  {
441  G4cout << " G4CT::CS End Position = "
443  G4cout << " G4CT::CS End Direction = "
445  }
446 #endif
448  {
449  // If the field can change energy, then the time must be integrated
450  // - so this should have been updated
451  //
453  fEndGlobalTimeComputed = true;
454 
455  // was ( fCandidateEndGlobalTime != track.GetGlobalTime() );
456  // a cleaner way is to have FieldTrack knowing whether time
457  // is updated
458  }
459  else
460  {
461  // The energy should be unchanged by field transport,
462  // - so the time changed will be calculated elsewhere
463  //
464  fEndGlobalTimeComputed = false;
465 
466  // Check that the integration preserved the energy
467  // - and if not correct this!
468  G4double startEnergy= track.GetKineticEnergy();
470 
471  static G4ThreadLocal G4int no_inexact_steps=0; // , no_large_ediff;
472  G4double absEdiff = std::fabs(startEnergy- endEnergy);
473  if( absEdiff > perMillion * endEnergy )
474  {
475  no_inexact_steps++;
476  // Possible statistics keeping here ...
477  }
478 #ifdef G4VERBOSE
479  if( (verboseLevel > 1) && ( absEdiff > perThousand * endEnergy) )
480  {
481  ReportInexactEnergy(startEnergy, endEnergy);
482  } // end of if (verboseLevel)
483 #endif
484  // Correct the energy for fields that conserve it
485  // This - hides the integration error
486  // - but gives a better physical answer
488  }
489  }
490 
491  fEndpointDistance = (fTransportEndPosition - startPosition).mag() ;
492  fTransportEndSpin = endTrackState.GetSpin();
493 
494  // Calculate the safety
495 
496  safetyProposal= startFullSafety; // used to be startMassSafety
497  // Changed to accomodate processes that cannot update the safety
498 
499  // Update safety for the end-point, if becomes negative at the end-point.
500 
501  if( (startFullSafety < fEndpointDistance )
502  && ( particleCharge != 0.0 ) ) // Only needed to prepare for MSC
503  // && !fAnyGeometryLimitedStep ) // To-Try: No safety update if at boundary
504  {
505  G4double endFullSafety =
507  // Expected mission -- only mass geometry's safety
508  // fMassNavigator->ComputeSafety( fTransportEndPosition) ;
509  // Yet discrete processes only have poststep -- and this cannot
510  // currently revise the safety
511  // ==> so we use the all-geometry safety as a precaution
512 
514  // Pushing safety to Helper avoids recalculation at this point
515 
516  G4ThreeVector centerPt= G4ThreeVector(0.0, 0.0, 0.0); // Used for return value
517  G4double endMassSafety= fPathFinder->ObtainSafety( fNavigatorId, centerPt);
518  // Retrieves the mass value from PathFinder (it calculated it)
519 
520  fPreviousMassSafety = endMassSafety ;
521  fPreviousFullSafety = endFullSafety;
522  fPreviousSftOrigin = fTransportEndPosition ;
523 
524  // The convention (Stepping Manager's) is safety from the start point
525  //
526  safetyProposal = endFullSafety + fEndpointDistance;
527  // --> was endMassSafety
528  // Changed to accomodate processes that cannot update the safety
529 
530 #ifdef G4DEBUG_TRANSPORT
531  G4int prec= G4cout.precision(12) ;
532  G4cout << "***CoupledTransportation::AlongStepGPIL ** " << G4endl ;
533  G4cout << " Revised Safety at endpoint " << fTransportEndPosition
534  << " give safety values: Mass= " << endMassSafety
535  << " All= " << endFullSafety << G4endl ;
536  G4cout << " Adding endpoint distance " << fEndpointDistance
537  << " to obtain pseudo-safety= " << safetyProposal << G4endl ;
538  G4cout.precision(prec);
539  }
540  else
541  {
542  G4int prec= G4cout.precision(12) ;
543  G4cout << "***CoupledTransportation::AlongStepGPIL ** " << G4endl ;
544  G4cout << " Quick Safety estimate at endpoint "
546  << " gives safety endpoint value = "
547  << startFullSafety - fEndpointDistance
548  << " using start-point value " << startFullSafety
549  << " and endpointDistance " << fEndpointDistance << G4endl;
550  G4cout.precision(prec);
551 #endif
552  }
553 
554  proposedSafetyForStart= safetyProposal;
555  fParticleChange.ProposeTrueStepLength(geometryStepLength) ;
556 
557  return geometryStepLength ;
558 }
559 
561 
564  const G4Step& stepData )
565 {
566  static G4ThreadLocal G4long noCallsCT_ASDI=0;
567  const char *methodName= "AlongStepDoIt";
568 
569  noCallsCT_ASDI++;
570 
571  fParticleChange.Initialize(track) ;
572  // sets all its members to the value of corresponding members in G4Track
573 
574  // Code specific for Transport
575  //
580 
582 
583  G4double deltaTime = 0.0 ;
584 
585  // Calculate Lab Time of Flight (ONLY if field Equations used it!)
586  // G4double endTime = fCandidateEndGlobalTime;
587  // G4double delta_time = endTime - startTime;
588 
589  G4double startTime = track.GetGlobalTime() ;
590 
592  {
593  G4double finalInverseVel= DBL_MAX, initialInverseVel=DBL_MAX;
594 
595  // The time was not integrated .. make the best estimate possible
596  //
597  G4double finalVelocity = track.GetVelocity() ;
598  if( finalVelocity > 0.0 ) { finalInverseVel= 1.0 / finalVelocity; }
599  G4double initialVelocity = stepData.GetPreStepPoint()->GetVelocity() ;
600  if( initialVelocity > 0.0 ) { initialInverseVel= 1.0 / initialVelocity; }
601  G4double stepLength = track.GetStepLength() ;
602 
603  if (finalVelocity > 0.0)
604  {
605  // deltaTime = stepLength/finalVelocity ;
606  G4double meanInverseVelocity = 0.5
607  * (initialInverseVel + finalInverseVel);
608  deltaTime = stepLength * meanInverseVelocity ;
609  }
610  else
611  {
612  deltaTime = stepLength * initialInverseVel ;
613  } // Could do with better estimate for final step (finalVelocity = 0) ?
614 
615  fCandidateEndGlobalTime = startTime + deltaTime ;
616  fParticleChange.ProposeLocalTime( track.GetLocalTime() + deltaTime) ;
617  }
618  else
619  {
620  deltaTime = fCandidateEndGlobalTime - startTime ;
622  }
623 
624  // Now Correct by Lorentz factor to get "proper" deltaTime
625 
626  G4double restMass = track.GetDynamicParticle()->GetMass() ;
627  G4double deltaProperTime = deltaTime*( restMass/track.GetTotalEnergy() ) ;
628 
629  fParticleChange.ProposeProperTime(track.GetProperTime() + deltaProperTime) ;
630  // fParticleChange. ProposeTrueStepLength( track.GetStepLength() ) ;
631 
632  // If the particle is caught looping or is stuck (in very difficult
633  // boundaries) in a magnetic field (doing many steps) THEN this kills it ...
634  //
635  if ( fParticleIsLooping )
636  {
638 
639  const G4ParticleDefinition* particleType=
640  track.GetDynamicParticle() -> GetParticleDefinition();
641  G4bool stable = particleType->GetPDGStable();
642 
643  G4bool candidateForEnd = (endEnergy < fThreshold_Important_Energy)
645 
646  if( candidateForEnd && stable )
647  {
648  const G4int electronPDG= 11; // G4Electron::G4Electron()->GetPDGEncoding();
649  G4int particlePDG= particleType->GetPDGEncoding();
650 
651  // Kill the looping particle
652  //
654 
655  // Simple statistics
656  fSumEnergyKilled += endEnergy;
657  fSumEnerSqKilled = endEnergy * endEnergy;
659 
660  if( endEnergy > fMaxEnergyKilled ) {
661  fMaxEnergyKilled = endEnergy;
662  fMaxEnergyKilledPDG = particlePDG;
663  }
664 
665  if( particleType->GetPDGEncoding() != electronPDG )
666  {
667  fSumEnergyKilled_NonElectron += endEnergy;
668  fSumEnerSqKilled_NonElectron += endEnergy * endEnergy;
670 
671  if( endEnergy > fMaxEnergyKilled_NonElectron )
672  {
673  fMaxEnergyKilled_NonElectron = endEnergy;
674  fMaxEnergyKilled_NonElecPDG = particlePDG;
675  }
676  }
677 
678  if( endEnergy > fThreshold_Warning_Energy && ! fSilenceLooperWarnings )
679  {
680  fpLogger->ReportLoopingTrack( track, stepData, fNoLooperTrials,
681  noCallsCT_ASDI, methodName );
682  }
683 
684  fNoLooperTrials=0;
685  }
686  else
687  {
688  fNoLooperTrials ++;
689 
691  if( fNoLooperTrials == 1 ) {
692  fSumEnergySaved += endEnergy;
693  if ( !stable )
694  fSumEnergyUnstableSaved += endEnergy;
695  }
696 #ifdef G4VERBOSE
697  if( verboseLevel > 2 && ! fSilenceLooperWarnings )
698  {
699  G4cout << " ** G4CoupledTransportation::AlongStepDoIt():"
700  << " Particle is looping but is saved ..." << G4endl
701  << " Number of trials (this track) = " << fNoLooperTrials
702  << G4endl
703  << " Steps by this track: " << track.GetCurrentStepNumber()
704  << G4endl
705  << " Total no of calls to this method (all tracks) = "
706  << noCallsCT_ASDI << G4endl;
707  }
708 #endif
709  }
710  }
711  else
712  {
713  fNoLooperTrials=0;
714  }
715 
716  // Another (sometimes better way) is to use a user-limit maximum Step size
717  // to alleviate this problem ..
718  // Add smooth curved trajectories to particle-change
719  //
720  // fParticleChange.SetPointerToVectorOfAuxiliaryPoints
721  // (fFieldPropagator->GimmeTrajectoryVectorAndForgetIt() );
722 
723  return &fParticleChange ;
724 }
725 
727 //
728 // This ensures that the PostStep action is always called,
729 // so that it can do the relocation if it is needed.
730 //
731 
734  G4double, // previousStepSize
735  G4ForceCondition* pForceCond )
736 {
737  // Must act as PostStep action -- to relocate particle
738  *pForceCond = Forced ;
739  return DBL_MAX ;
740 }
741 
743 
745 ReportMove( G4ThreeVector OldVector, G4ThreeVector NewVector,
746  const G4String& Quantity )
747 {
748  G4ThreeVector moveVec = ( NewVector - OldVector );
749 
750  G4cerr << G4endl
751  << "**************************************************************"
752  << G4endl;
753  G4cerr << "Endpoint has moved between value expected from TransportEndPosition "
754  << " and value from Track in PostStepDoIt. " << G4endl
755  << "Change of " << Quantity << " is " << moveVec.mag() / mm
756  << " mm long, "
757  << " and its vector is " << (1.0/mm) * moveVec << " mm " << G4endl
758  << "Endpoint of ComputeStep was " << OldVector
759  << " and current position to locate is " << NewVector << G4endl;
760 }
761 
763 
765  const G4Step& )
766 {
767  G4TouchableHandle retCurrentTouchable ; // The one to return
768 
769  // Initialize ParticleChange (by setting all its members equal
770  // to corresponding members in G4Track)
771  // fParticleChange.Initialize(track) ; // To initialise TouchableChange
772 
774 
776  {
778  }
779  else
780  {
782  }
783 
784  // Check that the end position and direction are preserved
785  // since call to AlongStepDoIt
786 
787 #ifdef G4DEBUG_TRANSPORT
788  if( ( verboseLevel > 0 )
789  && ((fTransportEndPosition - track.GetPosition()).mag2() >= 1.0e-16) )
790  {
792  "End of Step Position" );
793  G4cerr << " Problem in G4CoupledTransportation::PostStepDoIt " << G4endl;
794  }
795 
796  // If the Step was determined by the volume boundary, relocate the particle
797  // The pathFinder will know that the geometry limited the step (!?)
798 
799  if( verboseLevel > 0 )
800  {
801  G4cout << " Calling PathFinder::Locate() from "
802  << " G4CoupledTransportation::PostStepDoIt " << G4endl;
803  G4cout << " fAnyGeometryLimitedStep is " << fAnyGeometryLimitedStep
804  << G4endl;
805 
806  }
807 #endif
808 
810  {
811  fPathFinder->Locate( track.GetPosition(),
812  track.GetMomentumDirection(),
813  true);
814 
815  // fCurrentTouchable will now become the previous touchable,
816  // and what was the previous will be freed.
817  // (Needed because the preStepPoint can point to the previous touchable)
818 
821 
822 #ifdef G4DEBUG_TRANSPORT
823  if( verboseLevel > 0 )
824  {
825  G4cout << "G4CoupledTransportation::PostStepDoIt --- fNavigatorId = "
826  << fNavigatorId << G4endl;
827  }
828  if( verboseLevel > 1 )
829  {
831  G4cout << "CHECK !!!!!!!!!!! fCurrentTouchableHandle->GetVolume() = "
832  << vol;
833  if( vol ) { G4cout << "Name=" << vol->GetName(); }
834  G4cout << G4endl;
835  }
836 #endif
837 
838  // Check whether the particle is out of the world volume
839  // If so it has exited and must be killed.
840  //
841  if( fCurrentTouchableHandle->GetVolume() == 0 )
842  {
844  }
845  retCurrentTouchable = fCurrentTouchableHandle ;
846  // fParticleChange.SetTouchableHandle( fCurrentTouchableHandle ) ;
847  }
848  else // fAnyGeometryLimitedStep is false
849  {
850 #ifdef G4DEBUG_TRANSPORT
851  if( verboseLevel > 1 )
852  {
853  G4cout << "G4CoupledTransportation::PostStepDoIt -- "
854  << " fAnyGeometryLimitedStep = " << fAnyGeometryLimitedStep
855  << " must be false " << G4endl;
856  }
857 #endif
858  // This serves only to move each of the Navigator's location
859  //
860  // fLinearNavigator->LocateGlobalPointWithinVolume( track.GetPosition() ) ;
861 
862  fPathFinder->ReLocate( track.GetPosition() );
863  // track.GetMomentumDirection() );
864 
865  // Keep the value of the track's current Touchable is retained,
866  // and use it to overwrite the (unset) one in particle change.
867  // Expect this must be fCurrentTouchable too
868  // - could it be different, eg at the start of a step ?
869  //
870  retCurrentTouchable = track.GetTouchableHandle() ;
871  // fParticleChange.SetTouchableHandle( track.GetTouchableHandle() ) ;
872  } // endif ( fAnyGeometryLimitedStep )
873 
874 #ifdef G4DEBUG_NAVIGATION
875  G4cout << " CoupledTransport::AlongStep GPIL: "
876  << " last-step: any= " << fAnyGeometryLimitedStep
877  << " . ..... x . "
878  << " mass= " << fMassGeometryLimitedStep
879  << G4endl;
880 #endif
881 
884  else
886 
887  const G4VPhysicalVolume* pNewVol = retCurrentTouchable->GetVolume() ;
888  const G4Material* pNewMaterial = 0 ;
889  const G4VSensitiveDetector* pNewSensitiveDetector = 0 ;
890 
891  if( pNewVol != 0 )
892  {
893  pNewMaterial= pNewVol->GetLogicalVolume()->GetMaterial();
894  pNewSensitiveDetector= pNewVol->GetLogicalVolume()->GetSensitiveDetector();
895  }
896 
897  // ( const_cast<G4Material *> pNewMaterial ) ;
898  // ( const_cast<G4VSensitiveDetetor *> pNewSensitiveDetector) ;
899 
902  // "temporarily" until Get/Set Material of ParticleChange,
903  // and StepPoint can be made const.
904 
905  const G4MaterialCutsCouple* pNewMaterialCutsCouple = 0;
906  if( pNewVol != 0 )
907  {
908  pNewMaterialCutsCouple=pNewVol->GetLogicalVolume()->GetMaterialCutsCouple();
909  if( pNewMaterialCutsCouple!=0
910  && pNewMaterialCutsCouple->GetMaterial()!=pNewMaterial )
911  {
912  // for parametrized volume
913  //
914  pNewMaterialCutsCouple = G4ProductionCutsTable::GetProductionCutsTable()
915  ->GetMaterialCutsCouple(pNewMaterial,
916  pNewMaterialCutsCouple->GetProductionCuts());
917  }
918  }
919  fParticleChange.SetMaterialCutsCoupleInTouchable( pNewMaterialCutsCouple );
920 
921  // Must always set the touchable in ParticleChange, whether relocated or not
922  //
923  fParticleChange.SetTouchableHandle(retCurrentTouchable) ;
924 
925  return &fParticleChange ;
926 }
927 
929 // New method takes over the responsibility to reset the state of
930 // G4CoupledTransportation object:
931 // - at the start of a new track, and
932 // - on the resumption of a suspended track.
933 //
934 void
936 {
937 
938  G4TransportationManager* transportMgr =
940 
941  // G4VProcess::StartTracking(aTrack);
942  fNewTrack= true;
943 
944  // The 'initialising' actions
945  // once taken in AlongStepGPIL -- if ( track.GetCurrentStepNumber()==1 )
946 
947  // fStartedNewTrack= true;
948 
949  fMassNavigator = transportMgr->GetNavigatorForTracking() ;
951 
952  G4ThreeVector position = aTrack->GetPosition();
953  G4ThreeVector direction = aTrack->GetMomentumDirection();
954 
955  fPathFinder->PrepareNewTrack( position, direction);
956  // This implies a call to fPathFinder->Locate( position, direction );
957 
958  // Whether field exists should be determined at run level -- TODO
960 
961  // reset safety value and center
962  //
963  fPreviousMassSafety = 0.0 ;
964  fPreviousFullSafety = 0.0 ;
965  fPreviousSftOrigin = G4ThreeVector(0.,0.,0.) ;
966 
967  // reset looping counter -- for motion in field
968  fNoLooperTrials= 0;
969 
970  // Must clear this state .. else it depends on last track's value
971  // --> a better solution would set this from state of suspended track TODO ?
972  // Was if( aTrack->GetCurrentStepNumber()==1 ) { .. }
973 
974  // ChordFinder reset internal state
975  //
977  {
979  // Resets safety values, in case of overlaps.
980 
982  if( chordF ) { chordF->ResetStepEstimate(); }
983  }
984 
985  // Clear the chord finders of all fields (ie managers) derived objects
986  //
988  fieldMgrStore->ClearAllChordFindersState();
989 
990 #ifdef G4DEBUG_TRANSPORT
991  if( verboseLevel > 1 )
992  {
993  G4cout << " Returning touchable handle " << fCurrentTouchableHandle
994  << G4endl;
995  }
996 #endif
997 
998  // Update the current touchable handle (from the track's)
999  //
1001 }
1002 
1004 
1005 void
1007 {
1009  fPathFinder->EndTrack();
1010  // Resets TransportationManager to use ordinary Navigator
1011 }
1012 
1014 
1015 void
1017 ReportInexactEnergy(G4double startEnergy, G4double endEnergy)
1018 {
1019  static G4ThreadLocal G4int no_warnings= 0, warnModulo=1,
1020  moduloFactor= 10, no_large_ediff= 0;
1021 
1022  if( std::fabs(startEnergy- endEnergy) > perThousand * endEnergy )
1023  {
1024  no_large_ediff ++;
1025  if( (no_large_ediff% warnModulo) == 0 )
1026  {
1027  no_warnings++;
1028  std::ostringstream message;
1029  message << "Energy change in Step is above 1^-3 relative value. "
1030  << G4endl
1031  << " Relative change in 'tracking' step = "
1032  << std::setw(15) << (endEnergy-startEnergy)/startEnergy
1033  << G4endl
1034  << " Starting E= " << std::setw(12) << startEnergy / MeV
1035  << " MeV " << G4endl
1036  << " Ending E= " << std::setw(12) << endEnergy / MeV
1037  << " MeV " << G4endl
1038  << "Energy has been corrected -- however, review"
1039  << " field propagation parameters for accuracy." << G4endl;
1040  if ( (verboseLevel > 2 ) || (no_warnings<4)
1041  || (no_large_ediff == warnModulo * moduloFactor) )
1042  {
1043  message << "These include EpsilonStepMax(/Min) in G4FieldManager,"
1044  << G4endl
1045  << "which determine fractional error per step for integrated quantities."
1046  << G4endl
1047  << "Note also the influence of the permitted number of integration steps."
1048  << G4endl;
1049  }
1050  message << "Bad 'endpoint'. Energy change detected and corrected."
1051  << G4endl
1052  << "Has occurred already " << no_large_ediff << " times.";
1053  G4Exception("G4CoupledTransportation::AlongStepGetPIL()",
1054  "EnergyChange", JustWarning, message);
1055  if( no_large_ediff == warnModulo * moduloFactor )
1056  {
1057  warnModulo *= moduloFactor;
1058  }
1059  }
1060  }
1061 }
1062 
1064 
1066 {
1067  G4bool lastValue= fUseMagneticMoment;
1068  fUseMagneticMoment= useMoment;
1070  return lastValue;
1071 }
1072 
1074 //
1075 
1077 {
1078  G4bool lastValue= fUseGravity;
1079  fUseGravity= useGravity;
1080  G4Transportation::fUseGravity= useGravity;
1081  return lastValue;
1082 }
1083 
1085 //
1086 // Supress (or not) warnings about 'looping' particles
1087 
1089 {
1090  fSilenceLooperWarnings= val; // Flag to *Supress* all 'looper' warnings
1091  // G4CoupledTransportation::fSilenceLooperWarnings= val;
1092 }
1093 
1095 //
1097 {
1098  return fSilenceLooperWarnings;
1099 }
1100 
1102 //
1104 {
1105  // Setting old 'high' values for thresholds - old values, potentially appropriate
1106  // for the energy frontier HEP experiments
1107  SetThresholdWarningEnergy( 100.0 * CLHEP::MeV ); // Warn above this energy
1108  SetThresholdImportantEnergy( 250.0 * CLHEP::MeV ); // Give a few trial above this E);
1109 
1110  G4int maxTrials = 10;
1111  SetThresholdTrials( maxTrials );
1112 
1114 }
1115 
1117 void G4CoupledTransportation::SetLowLooperThresholds() // Values for low-E applications
1118 {
1119  // These values were the default in Geant4 10.5 - beta
1120  SetThresholdWarningEnergy( 1.0 * CLHEP::keV ); // Warn above this En
1121  SetThresholdImportantEnergy( 1.0 * CLHEP::MeV ); // Extra trials above it
1122 
1123  G4int maxTrials = 30; // A new value - was 10
1124  SetThresholdTrials( maxTrials );
1125 
1127 }
1128 
1130 //
1131 void
1133 {
1134  const char* message= "Logger object missing from G4CoupledTransportation";
1135  G4String classAndMethod= G4String("G4CoupledTransportation") + G4String( methodName );
1136  G4Exception(classAndMethod, "Missing Logger", JustWarning, message);
1137 
1139 }
1140 
1142 //
1143 void
1145 {
1146  PushThresholdsToLogger(); // To be absolutely certain they are in sync
1147  fpLogger->ReportLooperThresholds("G4CoupledTransportation");
1148 }