ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4ITTransportation.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file G4ITTransportation.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 //
30 //
31 // Contact : Mathieu Karamitros (kara (AT) cenbg . in2p3 . fr)
32 //
33 // History :
34 // -----------
35 // =======================================================================
36 // Modified:
37 // 28 Oct 2011, P.Gumpl./J.Ap: Detect gravity field, use magnetic moment
38 // 20 Nov 2008, J.Apostolakis: Push safety to helper - after ComputeSafety
39 // 9 Nov 2007, J.Apostolakis: Flag for short steps, push safety to helper
40 // 19 Jan 2006, P.MoraDeFreitas: Fix for suspended tracks (StartTracking)
41 // 11 Aug 2004, M.Asai: Add G4VSensitiveDetector* for updating stepPoint.
42 // 21 June 2003, J.Apostolakis: Calling field manager with
43 // track, to enable it to configure its accuracy
44 // 13 May 2003, J.Apostolakis: Zero field areas now taken into
45 // account correclty in all cases (thanks to W Pokorski).
46 // 29 June 2001, J.Apostolakis, D.Cote-Ahern, P.Gumplinger:
47 // correction for spin tracking
48 // 20 Febr 2001, J.Apostolakis: update for new FieldTrack
49 // 22 Sept 2000, V.Grichine: update of Kinetic Energy
50 // ---------------------------------------------------
51 // 10 Oct 2011, M.Karamitros: G4ITTransportation created
52 // Created: 19 March 1997, J. Apostolakis
53 // =======================================================================
54 //
55 // -------------------------------------------------------------------
56 
57 #include "G4ITTransportation.hh"
58 #include "G4IT.hh"
59 #include "G4TrackingInformation.hh"
60 #include "G4SystemOfUnits.hh"
63 #include "G4ProductionCutsTable.hh"
64 #include "G4ParticleTable.hh"
65 #include "G4ITNavigator.hh"
66 #include "G4PropagatorInField.hh"
67 #include "G4FieldManager.hh"
68 #include "G4ChordFinder.hh"
69 #include "G4ITSafetyHelper.hh"
70 #include "G4FieldManagerStore.hh"
71 
72 #include "G4UnitsTable.hh"
73 #include "G4ReferenceCast.hh"
74 
76 
77 #ifndef PrepareState
78 #define PrepareState() G4ITTransportationState* __state = this->GetState<G4ITTransportationState>();
79 #endif
80 
81 #ifndef State
82 #define State(theXInfo) (__state->theXInfo)
83 #endif
84 
85 //#define DEBUG_MEM
86 
87 #ifdef DEBUG_MEM
88 #include "G4MemStat.hh"
89 using namespace G4MemStat;
90 using G4MemStat::MemStat;
91 #endif
92 
93 //#define G4DEBUG_TRANSPORT 1
94 
97  fThreshold_Warning_Energy(100 * MeV),
98  fThreshold_Important_Energy(250 * MeV),
99  fThresholdTrials(10),
100  fUnimportant_Energy(1 * MeV), // Not used
101  fSumEnergyKilled(0.0),
102  fMaxEnergyKilled(0.0),
103  fShortStepOptimisation(false), // Old default: true (=fast short steps)
104  fVerboseLevel(verbose)
105 {
107  G4TransportationManager* transportMgr;
109  G4ITTransportationManager* ITtransportMgr;
111  fLinearNavigator = ITtransportMgr->GetNavigatorForTracking();
112  fFieldPropagator = transportMgr->GetPropagatorInField();
113  fpSafetyHelper = ITtransportMgr->GetSafetyHelper(); // New
114 
115  // Cannot determine whether a field exists here, as it would
116  // depend on the relative order of creating the detector's
117  // field and this process. That order is not guaranted.
118  // Instead later the method DoesGlobalFieldExist() is called
119 
120  enableAtRestDoIt = false;
121  enableAlongStepDoIt = true;
122  enablePostStepDoIt = true;
123  SetProcessSubType(60);
127 
129  /*
130  if(fTransportationState == 0)
131  {
132  G4cout << "KILL in G4ITTransportation::G4ITTransportation" << G4endl;
133  abort();
134  }
135  */
136 }
137 
139  G4VITProcess(right)
140 {
141  // Copy attributes
150 
151  // Setup Navigators
152  G4TransportationManager* transportMgr;
154  G4ITTransportationManager* ITtransportMgr;
156  fLinearNavigator = ITtransportMgr->GetNavigatorForTracking();
157  fFieldPropagator = transportMgr->GetPropagatorInField();
158  fpSafetyHelper = ITtransportMgr->GetSafetyHelper(); // New
159 
160  // Cannot determine whether a field exists here, as it would
161  // depend on the relative order of creating the detector's
162  // field and this process. That order is not guaranted.
163  // Instead later the method DoesGlobalFieldExist() is called
164 
165  enableAtRestDoIt = false;
166  enableAlongStepDoIt = true;
167  enablePostStepDoIt = true;
168 
173 }
174 
176 {
177 // if (this == &right) return *this;
178  return *this;
179 }
180 
185  G4ProcessState(), fCurrentTouchableHandle(0)
186 {
190  fTransportEndSpin = G4ThreeVector(0, 0, 0);
191  fMomentumChanged = false;
192  fEnergyChanged = false;
193  fEndGlobalTimeComputed = false;
195  fParticleIsLooping = false;
196 
197  static G4ThreadLocal G4TouchableHandle *nullTouchableHandle = 0;
198  if (!nullTouchableHandle) nullTouchableHandle = new G4TouchableHandle;
199  // Points to (G4VTouchable*) 0
200 
201  fCurrentTouchableHandle = *nullTouchableHandle;
202  fGeometryLimitedStep = false;
204  fPreviousSafety = 0.0;
205  fNoLooperTrials = false;
206  fEndPointDistance = -1;
207 }
208 
210 {
211  ;
212 }
213 
215 {
216 #ifdef G4VERBOSE
217  if ((fVerboseLevel > 0) && (fSumEnergyKilled > 0.0))
218  {
219  G4cout << " G4ITTransportation: Statistics for looping particles "
220  << G4endl;
221  G4cout << " Sum of energy of loopers killed: "
222  << fSumEnergyKilled << G4endl;
223  G4cout << " Max energy of loopers killed: "
224  << fMaxEnergyKilled << G4endl;
225  }
226 #endif
227 }
228 
230 {
232 }
233 
235 {
236  G4TransportationManager* transportMgr;
238 
239  // fFieldExists= transportMgr->GetFieldManager()->DoesFieldExist();
240  // return fFieldExists;
241  return transportMgr->GetFieldManager()->DoesFieldExist();
242 }
243 
245 //
246 // Responsibilities:
247 // Find whether the geometry limits the Step, and to what length
248 // Calculate the new value of the safety and return it.
249 // Store the final time, position and momentum.
250 G4double
253  G4double,
254  G4double currentMinimumStep,
255  G4double& currentSafety,
256  G4GPILSelection* selection)
257 {
258  PrepareState()
259  G4double geometryStepLength(-1.0), newSafety(-1.0);
260 
261  State(fParticleIsLooping) = false;
262  State(fEndGlobalTimeComputed) = false;
263  State(fGeometryLimitedStep) = false;
264 
265  // Initial actions moved to StartTrack()
266  // --------------------------------------
267  // Note: in case another process changes touchable handle
268  // it will be necessary to add here (for all steps)
269  // State(fCurrentTouchableHandle) = track.GetTouchableHandle();
270 
271  // GPILSelection is set to defaule value of CandidateForSelection
272  // It is a return value
273  //
274  *selection = CandidateForSelection;
275 
276  // Get initial Energy/Momentum of the track
277  //
278  const G4DynamicParticle* pParticle = track.GetDynamicParticle();
279 // const G4ParticleDefinition* pParticleDef = pParticle->GetDefinition() ;
280  G4ThreeVector startMomentumDir = pParticle->GetMomentumDirection();
281  G4ThreeVector startPosition = track.GetPosition();
282 
283  // G4double theTime = track.GetGlobalTime() ;
284 
285  // The Step Point safety can be limited by other geometries and/or the
286  // assumptions of any process - it's not always the geometrical safety.
287  // We calculate the starting point's isotropic safety here.
288  //
289  G4ThreeVector OriginShift = startPosition - State(fPreviousSftOrigin);
290  G4double MagSqShift = OriginShift.mag2();
291  if (MagSqShift >= sqr(State(fPreviousSafety)))
292  {
293  currentSafety = 0.0;
294  }
295  else
296  {
297  currentSafety = State(fPreviousSafety) - std::sqrt(MagSqShift);
298  }
299 
300  // Is the particle charged ?
301  //
302  G4double particleCharge = pParticle->GetCharge();
303 
304  // There is no need to locate the current volume. It is Done elsewhere:
305  // On track construction
306  // By the tracking, after all AlongStepDoIts, in "Relocation"
307 
308  // Check whether the particle have an (EM) field force exerting upon it
309  //
310  G4FieldManager* fieldMgr = 0;
311  G4bool fieldExertsForce = false;
312  if ((particleCharge != 0.0))
313  {
315  if (fieldMgr != 0)
316  {
317  // Message the field Manager, to configure it for this track
318  fieldMgr->ConfigureForTrack(&track);
319  // Moved here, in order to allow a transition
320  // from a zero-field status (with fieldMgr->(field)0
321  // to a finite field status
322 
323  // If the field manager has no field, there is no field !
324  fieldExertsForce = (fieldMgr->GetDetectorField() != 0);
325  }
326  }
327 
328  // G4cout << " G4Transport: field exerts force= " << fieldExertsForce
329  // << " fieldMgr= " << fieldMgr << G4endl;
330 
331  // Choose the calculation of the transportation: Field or not
332  //
333  if (!fieldExertsForce)
334  {
335  G4double linearStepLength;
336  if (fShortStepOptimisation && (currentMinimumStep <= currentSafety))
337  {
338  // The Step is guaranteed to be taken
339  //
340  geometryStepLength = currentMinimumStep;
341  State(fGeometryLimitedStep) = false;
342  }
343  else
344  {
345  // Find whether the straight path intersects a volume
346  //
347  // fLinearNavigator->SetNavigatorState(GetIT(track)->GetTrackingInfo()->GetNavigatorState());
348  linearStepLength = fLinearNavigator->ComputeStep(startPosition,
349  startMomentumDir,
350  currentMinimumStep,
351  newSafety);
352 
353 // G4cout << "linearStepLength : " << G4BestUnit(linearStepLength,"Length")
354 // << " | currentMinimumStep: " << currentMinimumStep
355 // << " | trackID: " << track.GetTrackID() << G4endl;
356 
357  // Remember last safety origin & value.
358  //
359  State(fPreviousSftOrigin) = startPosition;
360  State(fPreviousSafety) = newSafety;
361 
362  G4TrackStateManager& trackStateMan = GetIT(track)->GetTrackingInfo()
364  fpSafetyHelper->LoadTrackState(trackStateMan);
365  // fpSafetyHelper->SetTrackState(state);
366  fpSafetyHelper->SetCurrentSafety(newSafety,
367  State(fTransportEndPosition));
369 
370  // The safety at the initial point has been re-calculated:
371  //
372  currentSafety = newSafety;
373 
374  State(fGeometryLimitedStep) = (linearStepLength <= currentMinimumStep);
375  if (State(fGeometryLimitedStep))
376  {
377  // The geometry limits the Step size (an intersection was found.)
378  geometryStepLength = linearStepLength;
379  }
380  else
381  {
382  // The full Step is taken.
383  geometryStepLength = currentMinimumStep;
384  }
385  }
386  State(fEndPointDistance) = geometryStepLength;
387 
388  // Calculate final position
389  //
390  State(fTransportEndPosition) = startPosition
391  + geometryStepLength * startMomentumDir;
392 
393  // Momentum direction, energy and polarisation are unchanged by transport
394  //
395  State(fTransportEndMomentumDir) = startMomentumDir;
396  State(fTransportEndKineticEnergy) = track.GetKineticEnergy();
397  State(fTransportEndSpin) = track.GetPolarization();
398  State(fParticleIsLooping) = false;
399  State(fMomentumChanged) = false;
400  State(fEndGlobalTimeComputed) = true;
401  State(theInteractionTimeLeft) = State(fEndPointDistance)
402  / track.GetVelocity();
403  State(fCandidateEndGlobalTime) = State(theInteractionTimeLeft)
404  + track.GetGlobalTime();
405 /*
406  G4cout << "track.GetVelocity() : "
407  << track.GetVelocity() << G4endl;
408  G4cout << "State(endpointDistance) : "
409  << G4BestUnit(State(endpointDistance),"Length") << G4endl;
410  G4cout << "State(theInteractionTimeLeft) : "
411  << G4BestUnit(State(theInteractionTimeLeft),"Time") << G4endl;
412  G4cout << "track.GetGlobalTime() : "
413  << G4BestUnit(track.GetGlobalTime(),"Time") << G4endl;
414 */
415  }
416  else // A field exerts force
417  {
418 
419  G4ExceptionDescription exceptionDescription;
420  exceptionDescription
421  << "ITTransportation does not support external fields.";
422  exceptionDescription
423  << " If you are dealing with a tradiational MC simulation, ";
424  exceptionDescription << "please use G4Transportation.";
425 
426  G4Exception("G4ITTransportation::AlongStepGetPhysicalInteractionLength",
427  "NoExternalFieldSupport", FatalException, exceptionDescription);
428  /*
429  G4double momentumMagnitude = pParticle->GetTotalMomentum() ;
430  // G4ThreeVector EndUnitMomentum ;
431  G4double lengthAlongCurve ;
432  G4double restMass = pParticleDef->GetPDGMass() ;
433 
434  fFieldPropagator->SetChargeMomentumMass( particleCharge, // in e+ units
435  momentumMagnitude, // in Mev/c
436  restMass ) ;
437 
438  G4ThreeVector spin = track.GetPolarization() ;
439  G4FieldTrack aFieldTrack = G4FieldTrack( startPosition,
440  track.GetMomentumDirection(),
441  0.0,
442  track.GetKineticEnergy(),
443  restMass,
444  track.GetVelocity(),
445  track.GetGlobalTime(), // Lab.
446  track.GetProperTime(), // Part.
447  &spin ) ;
448  if( currentMinimumStep > 0 )
449  {
450  // Do the Transport in the field (non recti-linear)
451  //
452  lengthAlongCurve = fFieldPropagator->ComputeStep( aFieldTrack,
453  currentMinimumStep,
454  currentSafety,
455  track.GetVolume() ) ;
456  State(fGeometryLimitedStep)= lengthAlongCurve < currentMinimumStep;
457  if( State(fGeometryLimitedStep) )
458  {
459  geometryStepLength = lengthAlongCurve ;
460  }
461  else
462  {
463  geometryStepLength = currentMinimumStep ;
464  }
465 
466  // Remember last safety origin & value.
467  //
468  State(fPreviousSftOrigin) = startPosition ;
469  State(fPreviousSafety) = currentSafety ;
470  fpSafetyHelper->SetCurrentSafety( newSafety, startPosition);
471  }
472  else
473  {
474  geometryStepLength = lengthAlongCurve= 0.0 ;
475  State(fGeometryLimitedStep) = false ;
476  }
477 
478  // Get the End-Position and End-Momentum (Dir-ection)
479  //
480  State(fTransportEndPosition) = aFieldTrack.GetPosition() ;
481 
482  // Momentum: Magnitude and direction can be changed too now ...
483  //
484  State(fMomentumChanged) = true ;
485  State(fTransportEndMomentumDir) = aFieldTrack.GetMomentumDir() ;
486 
487  State(fTransportEndKineticEnergy) = aFieldTrack.GetKineticEnergy() ;
488 
489  if( fFieldPropagator->GetCurrentFieldManager()->DoesFieldChangeEnergy() )
490  {
491  // If the field can change energy, then the time must be integrated
492  // - so this should have been updated
493  //
494  State(fCandidateEndGlobalTime) = aFieldTrack.GetLabTimeOfFlight();
495  State(fEndGlobalTimeComputed) = true;
496 
497  State(theInteractionTimeLeft) = State(fCandidateEndGlobalTime) -
498  track.GetGlobalTime() ;
499 
500  // was ( State(fCandidateEndGlobalTime) != track.GetGlobalTime() );
501  // a cleaner way is to have FieldTrack knowing whether time is updated.
502  }
503  else
504  {
505  // The energy should be unchanged by field transport,
506  // - so the time changed will be calculated elsewhere
507  //
508  State(fEndGlobalTimeComputed) = false;
509 
510  // Check that the integration preserved the energy
511  // - and if not correct this!
512  G4double startEnergy= track.GetKineticEnergy();
513  G4double endEnergy= State(fTransportEndKineticEnergy);
514 
515  static G4int no_inexact_steps=0, no_large_ediff;
516  G4double absEdiff = std::fabs(startEnergy- endEnergy);
517  if( absEdiff > perMillion * endEnergy )
518  {
519  no_inexact_steps++;
520  // Possible statistics keeping here ...
521  }
522  #ifdef G4VERBOSE
523  if( fVerboseLevel > 1 )
524  {
525  if( std::fabs(startEnergy- endEnergy) > perThousand * endEnergy )
526  {
527  static G4int no_warnings= 0, warnModulo=1, moduloFactor= 10;
528  no_large_ediff ++;
529  if( (no_large_ediff% warnModulo) == 0 )
530  {
531  no_warnings++;
532  G4cout << "WARNING - G4Transportation::AlongStepGetPIL() "
533  << " Energy change in Step is above 1^-3 relative value. " << G4endl
534  << " Relative change in 'tracking' step = "
535  << std::setw(15) << (endEnergy-startEnergy)/startEnergy << G4endl
536  << " Starting E= " << std::setw(12) << startEnergy / MeV << " MeV "
537  << G4endl
538  << " Ending E= " << std::setw(12) << endEnergy / MeV << " MeV "
539  << G4endl;
540  G4cout << " Energy has been corrected -- however, review"
541  << " field propagation parameters for accuracy." << G4endl;
542  if( (fVerboseLevel > 2 ) || (no_warnings<4) ||
543  (no_large_ediff == warnModulo * moduloFactor) )
544  {
545  G4cout << " These include EpsilonStepMax(/Min) in G4FieldManager "
546  << " which determine fractional error per step for integrated quantities. "
547  << G4endl
548  << " Note also the influence of the permitted number of integration steps."
549  << G4endl;
550  }
551  G4cerr << "ERROR - G4Transportation::AlongStepGetPIL()" << G4endl
552  << " Bad 'endpoint'. Energy change detected"
553  << " and corrected. "
554  << " Has occurred already "
555  << no_large_ediff << " times." << G4endl;
556  if( no_large_ediff == warnModulo * moduloFactor )
557  {
558  warnModulo *= moduloFactor;
559  }
560  }
561  }
562  } // end of if (fVerboseLevel)
563  #endif
564  // Correct the energy for fields that conserve it
565  // This - hides the integration error
566  // - but gives a better physical answer
567  State(fTransportEndKineticEnergy)= track.GetKineticEnergy();
568  }
569 
570  State(fTransportEndSpin) = aFieldTrack.GetSpin();
571  State(fParticleIsLooping) = fFieldPropagator->IsParticleLooping() ;
572  State(endpointDistance) = (State(fTransportEndPosition) -
573  startPosition).mag() ;
574  // State(theInteractionTimeLeft) =
575  track.GetVelocity()/State(endpointDistance) ;
576  */
577  }
578 
579  // If we are asked to go a step length of 0, and we are on a boundary
580  // then a boundary will also limit the step -> we must flag this.
581  //
582  if (currentMinimumStep == 0.0)
583  {
584  if (currentSafety == 0.0)
585  {
586  State(fGeometryLimitedStep) = true;
587 // G4cout << "!!!! Safety is NULL, on the Boundary !!!!!" << G4endl;
588 // G4cout << " Track position : " << track.GetPosition() /nanometer
589 // << G4endl;
590  }
591  }
592 
593  // Update the safety starting from the end-point,
594  // if it will become negative at the end-point.
595  //
596  if (currentSafety < State(fEndPointDistance))
597  {
598  // if( particleCharge == 0.0 )
599  // G4cout << " Avoiding call to ComputeSafety : charge = 0.0 " << G4endl;
600 
601  if (particleCharge != 0.0)
602  {
603 
604  G4double endSafety = fLinearNavigator->ComputeSafety(
605  State(fTransportEndPosition));
606  currentSafety = endSafety;
607  State(fPreviousSftOrigin) = State(fTransportEndPosition);
608  State(fPreviousSafety) = currentSafety;
609 
610  /*
611  G4VTrackStateHandle state =
612  GetIT(track)->GetTrackingInfo()->GetTrackState(fpSafetyHelper);
613  */
614  G4TrackStateManager& trackStateMan = GetIT(track)->GetTrackingInfo()
616  fpSafetyHelper->LoadTrackState(trackStateMan);
617  // fpSafetyHelper->SetTrackState(state);
618  fpSafetyHelper->SetCurrentSafety(currentSafety,
619  State(fTransportEndPosition));
621 
622  // Because the Stepping Manager assumes it is from the start point,
623  // add the StepLength
624  //
625  currentSafety += State(fEndPointDistance);
626 
627 #ifdef G4DEBUG_TRANSPORT
628  G4cout.precision(12);
629  G4cout << "***G4Transportation::AlongStepGPIL ** " << G4endl;
630  G4cout << " Called Navigator->ComputeSafety at "
631  << State(fTransportEndPosition)
632  << " and it returned safety= " << endSafety << G4endl;
633  G4cout << " Adding endpoint distance " << State(fEndPointDistance)
634  << " to obtain pseudo-safety= " << currentSafety << G4endl;
635 #endif
636  }
637  }
638 
639  // fParticleChange.ProposeTrueStepLength(geometryStepLength) ;
640 
641 // G4cout << "G4ITTransportation::AlongStepGetPhysicalInteractionLength = "
642 // << G4BestUnit(geometryStepLength,"Length") << G4endl;
643 
644  return geometryStepLength;
645 }
646 
648  const G4Step& /*step*/,
649  const double timeStep,
650  double& oPhysicalStep)
651 {
652  PrepareState()
653  const G4DynamicParticle* pParticle = track.GetDynamicParticle();
654  G4ThreeVector startMomentumDir = pParticle->GetMomentumDirection();
655  G4ThreeVector startPosition = track.GetPosition();
656 
657  track.CalculateVelocity();
658  G4double initialVelocity = track.GetVelocity();
659 
660  State(fGeometryLimitedStep) = false;
661 
663  // !!! CASE NO FIELD !!!
665  State(fCandidateEndGlobalTime) = timeStep + track.GetGlobalTime();
666  State(fEndGlobalTimeComputed) = true;
667 
668  // Choose the calculation of the transportation: Field or not
669  //
670  if (!State(fMomentumChanged))
671  {
672  // G4cout << "Momentum has not changed" << G4endl;
673  fParticleChange.ProposeVelocity(initialVelocity);
674  oPhysicalStep = initialVelocity * timeStep;
675 
676  // Calculate final position
677  //
678  State(fTransportEndPosition) = startPosition
679  + oPhysicalStep * startMomentumDir;
680  }
681 }
682 
684 //
685 // Initialize ParticleChange (by setting all its members equal
686 // to corresponding members in G4Track)
687 #include "G4ParticleTable.hh"
689  const G4Step& stepData)
690 {
691 
692 #if defined (DEBUG_MEM)
693  MemStat mem_first, mem_second, mem_diff;
694 #endif
695 
696 #if defined (DEBUG_MEM)
697  mem_first = MemoryUsage();
698 #endif
699 
700  PrepareState()
701 
702  // G4cout << "G4ITTransportation::AlongStepDoIt" << G4endl;
703  // set pdefOpticalPhoton
704  // Andrea Dotti: the following statement should be in a single line:
705  // G4-MT transformation tools get confused if statement spans two lines
706  // If needed contact: adotti@slac.stanford.edu
707  static G4ThreadLocal G4ParticleDefinition* pdefOpticalPhoton = 0;
708  if (!pdefOpticalPhoton) pdefOpticalPhoton =
710 
711  static G4ThreadLocal G4int noCalls = 0;
712  noCalls++;
713 
715 
716  // Code for specific process
717  //
718  fParticleChange.ProposePosition(State(fTransportEndPosition));
719  fParticleChange.ProposeMomentumDirection(State(fTransportEndMomentumDir));
720  fParticleChange.ProposeEnergy(State(fTransportEndKineticEnergy));
721  fParticleChange.SetMomentumChanged(State(fMomentumChanged));
722 
723  fParticleChange.ProposePolarization(State(fTransportEndSpin));
724 
725  G4double deltaTime = 0.0;
726 
727  // Calculate Lab Time of Flight (ONLY if field Equations used it!)
728  // G4double endTime = State(fCandidateEndGlobalTime);
729  // G4double delta_time = endTime - startTime;
730 
731  G4double startTime = track.GetGlobalTime();
735  if (State(fEndGlobalTimeComputed) == false)
736  {
737  // The time was not integrated .. make the best estimate possible
738  //
739  G4double initialVelocity = stepData.GetPreStepPoint()->GetVelocity();
740  G4double stepLength = track.GetStepLength();
741 
742  deltaTime = 0.0; // in case initialVelocity = 0
743  if (track.GetParticleDefinition() == pdefOpticalPhoton)
744  {
745  // For only Optical Photon, final velocity is used
746  double finalVelocity = track.CalculateVelocityForOpticalPhoton();
747  fParticleChange.ProposeVelocity(finalVelocity);
748  deltaTime = stepLength / finalVelocity;
749  }
750  else if (initialVelocity > 0.0)
751  {
752  deltaTime = stepLength / initialVelocity;
753  }
754 
755  State(fCandidateEndGlobalTime) = startTime + deltaTime;
756  }
757  else
758  {
759  deltaTime = State(fCandidateEndGlobalTime) - startTime;
760  }
761 
762  fParticleChange.ProposeGlobalTime(State(fCandidateEndGlobalTime));
763  fParticleChange.ProposeLocalTime(track.GetLocalTime() + deltaTime);
764  /*
765  // Now Correct by Lorentz factor to get delta "proper" Time
766 
767  G4double restMass = track.GetDynamicParticle()->GetMass() ;
768  G4double deltaProperTime = deltaTime*( restMass/track.GetTotalEnergy() ) ;
769 
770  fParticleChange.ProposeProperTime(track.GetProperTime() + deltaProperTime) ;
771  */
772 
774 
777 
778  // If the particle is caught looping or is stuck (in very difficult
779  // boundaries) in a magnetic field (doing many steps)
780  // THEN this kills it ...
781  //
782  if (State(fParticleIsLooping))
783  {
784  G4double endEnergy = State(fTransportEndKineticEnergy);
785 
786  if ((endEnergy < fThreshold_Important_Energy) || (State(fNoLooperTrials)
787  >= fThresholdTrials))
788  {
789  // Kill the looping particle
790  //
791  // G4cout << "G4ITTransportation will killed the molecule"<< G4endl;
793 
794  // 'Bare' statistics
795  fSumEnergyKilled += endEnergy;
796  if (endEnergy > fMaxEnergyKilled)
797  {
798  fMaxEnergyKilled = endEnergy;
799  }
800 
801 #ifdef G4VERBOSE
802  if ((fVerboseLevel > 1) || (endEnergy > fThreshold_Warning_Energy))
803  {
804  G4cout
805  << " G4ITTransportation is killing track that is looping or stuck "
806  << G4endl<< " This track has " << track.GetKineticEnergy() / MeV
807  << " MeV energy." << G4endl;
808  G4cout << " Number of trials = " << State(fNoLooperTrials)
809  << " No of calls to AlongStepDoIt = " << noCalls
810  << G4endl;
811  }
812 #endif
813  State(fNoLooperTrials) = 0;
814  }
815  else
816  {
817  State(fNoLooperTrials)++;
818 #ifdef G4VERBOSE
819  if ((fVerboseLevel > 2))
820  {
821  G4cout << " G4ITTransportation::AlongStepDoIt(): Particle looping - "
822  << " Number of trials = " << State(fNoLooperTrials)
823  << " No of calls to = " << noCalls << G4endl;
824  }
825 #endif
826  }
827  }
828  else
829  {
830  State(fNoLooperTrials)=0;
831  }
832 
833  // Another (sometimes better way) is to use a user-limit maximum Step size
834  // to alleviate this problem ..
835 
836  // Introduce smooth curved trajectories to particle-change
837  //
840 
841 #if defined (DEBUG_MEM)
842  mem_second = MemoryUsage();
843  mem_diff = mem_second-mem_first;
844  G4cout << "\t || MEM || End of G4ITTransportation::AlongStepDoIt, diff is: "
845  << mem_diff << G4endl;
846 #endif
847 
848  return &fParticleChange;
849 }
850 
852 //
853 // This ensures that the PostStep action is always called,
854 // so that it can do the relocation if it is needed.
855 //
856 
857 G4double
860  G4double, // previousStepSize
861  G4ForceCondition* pForceCond)
862 {
863  *pForceCond = Forced;
864  return DBL_MAX; // was kInfinity ; but convention now is DBL_MAX
865 }
866 
868 //
869 
871  const G4Step&)
872 {
873  // G4cout << "G4ITTransportation::PostStepDoIt" << G4endl;
874 
875  PrepareState()
876  G4TouchableHandle retCurrentTouchable; // The one to return
877  G4bool isLastStep = false;
878 
879  // Initialize ParticleChange (by setting all its members equal
880  // to corresponding members in G4Track)
881  fParticleChange.Initialize(track); // To initialise TouchableChange
882 
884 
885  // If the Step was determined by the volume boundary,
886  // logically relocate the particle
887 
888  if (State(fGeometryLimitedStep))
889  {
890 
891  if(fVerboseLevel)
892  {
893  G4cout << "Step is limited by geometry "
894  << "track ID : " << track.GetTrackID() << G4endl;
895  }
896 
897  // fCurrentTouchable will now become the previous touchable,
898  // and what was the previous will be freed.
899  // (Needed because the preStepPoint can point to the previous touchable)
900 
901  if ( State(fCurrentTouchableHandle)->GetVolume() == 0)
902  {
903  G4ExceptionDescription exceptionDescription;
904  exceptionDescription << "No current touchable found ";
905  G4Exception(" G4ITTransportation::PostStepDoIt", "G4ITTransportation001",
906  FatalErrorInArgument, exceptionDescription);
907  }
908 
909  fLinearNavigator->SetGeometricallyLimitedStep();
910  fLinearNavigator->LocateGlobalPointAndUpdateTouchableHandle(
911  track.GetPosition(), track.GetMomentumDirection(),
912  State(fCurrentTouchableHandle), true);
913  // Check whether the particle is out of the world volume
914  // If so it has exited and must be killed.
915  //
916  if ( State(fCurrentTouchableHandle)->GetVolume() == 0)
917  {
918  // abort();
919 #ifdef G4VERBOSE
920  if (fVerboseLevel > 0)
921  {
922  G4cout << "Track position : " << track.GetPosition() / nanometer
923  << " [nm]" << " Track ID : " << track.GetTrackID() << G4endl;
924  G4cout << "G4ITTransportation will killed the track because "
925  "State(fCurrentTouchableHandle)->GetVolume() == 0"<< G4endl;
926  }
927 #endif
929  }
930 
931  retCurrentTouchable = State(fCurrentTouchableHandle);
932 
933 // G4cout << "Current volume : " << track.GetVolume()->GetName()
934 // << " Next volume : "
935 // << (State(fCurrentTouchableHandle)->GetVolume() ?
936 // State(fCurrentTouchableHandle)->GetVolume()->GetName():"OutWorld")
937 // << " Position : " << track.GetPosition() / nanometer
938 // << " track ID : " << track.GetTrackID()
939 // << G4endl;
940 
941  fParticleChange.SetTouchableHandle(State(fCurrentTouchableHandle));
942 
943  // Update the Step flag which identifies the Last Step in a volume
944  isLastStep = fLinearNavigator->ExitedMotherVolume()
945  | fLinearNavigator->EnteredDaughterVolume();
946 
947 #ifdef G4DEBUG_TRANSPORT
948  // Checking first implementation of flagging Last Step in Volume
949  G4bool exiting = fLinearNavigator->ExitedMotherVolume();
950  G4bool entering = fLinearNavigator->EnteredDaughterVolume();
951 
952  if( ! (exiting || entering) )
953  {
954  G4cout << " Transport> : Proposed isLastStep= " << isLastStep
955  << " Exiting " << fLinearNavigator->ExitedMotherVolume()
956  << " Entering " << fLinearNavigator->EnteredDaughterVolume()
957  << " Track position : " << track.GetPosition() /nanometer << " [nm]"
958  << G4endl;
959  G4cout << " Track position : " << track.GetPosition() /nanometer
960  << G4endl;
961  }
962 #endif
963  }
964  else // fGeometryLimitedStep is false
965  {
966  // This serves only to move the Navigator's location
967  //
968 // abort();
969  fLinearNavigator->LocateGlobalPointWithinVolume(track.GetPosition());
970 
971  // The value of the track's current Touchable is retained.
972  // (and it must be correct because we must use it below to
973  // overwrite the (unset) one in particle change)
974  // It must be fCurrentTouchable too ??
975  //
977  retCurrentTouchable = track.GetTouchableHandle();
978 
979  isLastStep = false;
980 #ifdef G4DEBUG_TRANSPORT
981  // Checking first implementation of flagging Last Step in Volume
982  G4cout << " Transport> Proposed isLastStep= " << isLastStep
983  << " Geometry did not limit step. Position : "
984  << track.GetPosition()/ nanometer << G4endl;
985 #endif
986  } // endif ( fGeometryLimitedStep )
987 
989 
990  const G4VPhysicalVolume* pNewVol = retCurrentTouchable->GetVolume();
991  const G4Material* pNewMaterial = 0;
992  const G4VSensitiveDetector* pNewSensitiveDetector = 0;
993 
994  if (pNewVol != 0)
995  {
996  pNewMaterial = pNewVol->GetLogicalVolume()->GetMaterial();
997  pNewSensitiveDetector = pNewVol->GetLogicalVolume()->GetSensitiveDetector();
998  }
999 
1000  // ( <const_cast> pNewMaterial ) ;
1001  // ( <const_cast> pNewSensitiveDetector) ;
1002 
1005  (G4VSensitiveDetector *) pNewSensitiveDetector);
1006 
1007  const G4MaterialCutsCouple* pNewMaterialCutsCouple = 0;
1008  if (pNewVol != 0)
1009  {
1010  pNewMaterialCutsCouple =
1012  }
1013 
1014  if (pNewVol != 0 && pNewMaterialCutsCouple != 0
1015  && pNewMaterialCutsCouple->GetMaterial() != pNewMaterial)
1016  {
1017  // for parametrized volume
1018  //
1019  pNewMaterialCutsCouple = G4ProductionCutsTable::GetProductionCutsTable()
1020  ->GetMaterialCutsCouple(pNewMaterial,
1021  pNewMaterialCutsCouple->GetProductionCuts());
1022  }
1023  fParticleChange.SetMaterialCutsCoupleInTouchable(pNewMaterialCutsCouple);
1024 
1025  // temporarily until Get/Set Material of ParticleChange,
1026  // and StepPoint can be made const.
1027  // Set the touchable in ParticleChange
1028  // this must always be done because the particle change always
1029  // uses this value to overwrite the current touchable pointer.
1030  //
1031  fParticleChange.SetTouchableHandle(retCurrentTouchable);
1032 
1033  return &fParticleChange;
1034 }
1035 
1036 // New method takes over the responsibility to reset the state of
1037 // G4Transportation object at the start of a new track or the resumption of
1038 // a suspended track.
1039 
1041 {
1044  {
1045 // G4VITProcess::fpState = new G4ITTransportationState();
1047  // Will set in the same time fTransportationState
1048  }
1049 
1052  GetIT(track)->GetTrackingInfo()->GetTrackStateManager());
1053 
1054  // The actions here are those that were taken in AlongStepGPIL
1055  // when track.GetCurrentStepNumber()==1
1056 
1057  // reset safety value and center
1058  //
1059  // State(fPreviousSafety) = 0.0 ;
1060  // State(fPreviousSftOrigin) = G4ThreeVector(0.,0.,0.) ;
1061 
1062  // reset looping counter -- for motion in field
1063  // State(fNoLooperTrials)= 0;
1064  // Must clear this state .. else it depends on last track's value
1065  // --> a better solution would set this from state of suspended track TODO ?
1066  // Was if( aTrack->GetCurrentStepNumber()==1 ) { .. }
1067 
1068  // ChordFinder reset internal state
1069  //
1070  if (DoesGlobalFieldExist())
1071  {
1073  // Resets all state of field propagator class (ONLY)
1074  // including safety values (in case of overlaps and to wipe for first track).
1075 
1076  // G4ChordFinder* chordF= fFieldPropagator->GetChordFinder();
1077  // if( chordF ) chordF->ResetStepEstimate();
1078  }
1079 
1080  // Make sure to clear the chord finders of all fields (ie managers)
1081  static G4ThreadLocal G4FieldManagerStore* fieldMgrStore = 0;
1082  if (!fieldMgrStore) fieldMgrStore = G4FieldManagerStore::GetInstance();
1083  fieldMgrStore->ClearAllChordFindersState();
1084 
1085  // Update the current touchable handle (from the track's)
1086  //
1087  PrepareState()
1088  State(fCurrentTouchableHandle) = track->GetTouchableHandle();
1089 
1091 }
1092 
1093 #undef State
1094 #undef PrepareState