Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/processes/electromagnetic/utils/src/G4TransportationWithMsc.cc

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

Diff markup

Differences between /processes/electromagnetic/utils/src/G4TransportationWithMsc.cc (Version 11.3.0) and /processes/electromagnetic/utils/src/G4TransportationWithMsc.cc (Version 11.1.3)


  1 //                                                  1 //
  2 // *******************************************      2 // ********************************************************************
  3 // * License and Disclaimer                         3 // * License and Disclaimer                                           *
  4 // *                                                4 // *                                                                  *
  5 // * The  Geant4 software  is  copyright of th      5 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
  6 // * the Geant4 Collaboration.  It is provided      6 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
  7 // * conditions of the Geant4 Software License      7 // * conditions of the Geant4 Software License,  included in the file *
  8 // * LICENSE and available at  http://cern.ch/      8 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
  9 // * include a list of copyright holders.           9 // * include a list of copyright holders.                             *
 10 // *                                               10 // *                                                                  *
 11 // * Neither the authors of this software syst     11 // * Neither the authors of this software system, nor their employing *
 12 // * institutes,nor the agencies providing fin     12 // * institutes,nor the agencies providing financial support for this *
 13 // * work  make  any representation or  warran     13 // * work  make  any representation or  warranty, express or implied, *
 14 // * regarding  this  software system or assum     14 // * regarding  this  software system or assume any liability for its *
 15 // * use.  Please see the license in the file      15 // * use.  Please see the license in the file  LICENSE  and URL above *
 16 // * for the full disclaimer and the limitatio     16 // * for the full disclaimer and the limitation of liability.         *
 17 // *                                               17 // *                                                                  *
 18 // * This  code  implementation is the result      18 // * This  code  implementation is the result of  the  scientific and *
 19 // * technical work of the GEANT4 collaboratio     19 // * technical work of the GEANT4 collaboration.                      *
 20 // * By using,  copying,  modifying or  distri     20 // * By using,  copying,  modifying or  distributing the software (or *
 21 // * any work based  on the software)  you  ag     21 // * any work based  on the software)  you  agree  to acknowledge its *
 22 // * use  in  resulting  scientific  publicati     22 // * use  in  resulting  scientific  publications,  and indicate your *
 23 // * acceptance of all terms of the Geant4 Sof     23 // * acceptance of all terms of the Geant4 Software license.          *
 24 // *******************************************     24 // ********************************************************************
 25 //                                                 25 //
 26 // G4TransportationWithMsc                         26 // G4TransportationWithMsc
 27 //                                                 27 //
 28 // Class Description:                              28 // Class Description:
 29 //                                                 29 //
 30 // It is a generic process of transportation w     30 // It is a generic process of transportation with multiple scattering included
 31 // in the step limitation and propagation.         31 // in the step limitation and propagation.
 32 //                                                 32 //
 33 // Original author: Jonas Hahnfeld, 2022           33 // Original author: Jonas Hahnfeld, 2022
 34                                                    34 
 35 // -------------------------------------------     35 // -------------------------------------------------------------------
 36 //                                                 36 //
 37 //....oooOO0OOooo........oooOO0OOooo........oo     37 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
 38 //....oooOO0OOooo........oooOO0OOooo........oo     38 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
 39                                                    39 
 40 #include "G4TransportationWithMsc.hh"              40 #include "G4TransportationWithMsc.hh"
 41                                                    41 
 42 #include "G4DynamicParticle.hh"                << 
 43 #include "G4Electron.hh"                       << 
 44 #include "G4EmConfigurator.hh"                 << 
 45 #include "G4EmDataHandler.hh"                  << 
 46 #include "G4LossTableBuilder.hh"                   42 #include "G4LossTableBuilder.hh"
 47 #include "G4LossTableManager.hh"                   43 #include "G4LossTableManager.hh"
 48 #include "G4ParticleChangeForGamma.hh"         <<  44 #include "G4EmConfigurator.hh"
                                                   >>  45 #include "G4VMscModel.hh"
                                                   >>  46 
 49 #include "G4ParticleChangeForMSC.hh"               47 #include "G4ParticleChangeForMSC.hh"
 50 #include "G4PhysicalConstants.hh"              <<  48 
 51 #include "G4PhysicsTableHelper.hh"             <<  49 #include "G4DynamicParticle.hh"
 52 #include "G4PhysicsVector.hh"                  << 
 53 #include "G4ProductionCutsTable.hh"            << 
 54 #include "G4Step.hh"                               50 #include "G4Step.hh"
 55 #include "G4StepPoint.hh"                          51 #include "G4StepPoint.hh"
 56 #include "G4StepStatus.hh"                         52 #include "G4StepStatus.hh"
 57 #include "G4Track.hh"                              53 #include "G4Track.hh"
 58 #include "G4TransportationProcessType.hh"      <<  54 
 59 #include "G4VMscModel.hh"                      <<  55 #include "G4Electron.hh"
                                                   >>  56 
                                                   >>  57 #include "G4PhysicalConstants.hh"
 60                                                    58 
 61 //....oooOO0OOooo........oooOO0OOooo........oo     59 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
 62                                                    60 
 63 static constexpr G4double kLowestKinEnergy = 1 <<  61 static constexpr G4double kLowestKinEnergy  = 10 * CLHEP::eV;
 64 static constexpr G4double kGeomMin = 0.05 * CL <<  62 static constexpr G4double kGeomMin          = 0.05 * CLHEP::nm;
 65 static constexpr G4double kMinDisplacement2 =      63 static constexpr G4double kMinDisplacement2 = kGeomMin * kGeomMin;
 66                                                    64 
 67 //....oooOO0OOooo........oooOO0OOooo........oo     65 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
 68                                                    66 
 69 G4TransportationWithMsc::G4TransportationWithM <<  67 G4TransportationWithMsc::G4TransportationWithMsc(ScatteringType type,
 70   : G4Transportation(verbosity, "Transportatio <<  68                                                  G4int verbosity)
                                                   >>  69   : G4Transportation(verbosity, "TransportationWithMsc")
                                                   >>  70   , fType(type)
 71 {                                                  71 {
 72   SetProcessSubType(static_cast<G4int>(TRANSPO << 
 73   SetVerboseLevel(1);                              72   SetVerboseLevel(1);
 74                                                    73 
 75   fEmManager = G4LossTableManager::Instance(); <<  74   fEmManager    = G4LossTableManager::Instance();
 76   fModelManager = new G4EmModelManager;            75   fModelManager = new G4EmModelManager;
 77                                                    76 
 78   if (type == ScatteringType::MultipleScatteri <<  77   if(type == ScatteringType::MultipleScattering)
                                                   >>  78   {
 79     fParticleChangeForMSC = new G4ParticleChan     79     fParticleChangeForMSC = new G4ParticleChangeForMSC;
 80   }                                                80   }
 81   else if (type == ScatteringType::SingleScatt << 
 82     fParticleChangeForSS = new G4ParticleChang << 
 83     fSecondariesSS = new std::vector<G4Dynamic << 
 84   }                                            << 
 85                                                    81 
 86   G4ThreeVector zero;                              82   G4ThreeVector zero;
 87   fSubStepDynamicParticle = new G4DynamicParti <<  83   fSubStepDynamicParticle =
                                                   >>  84     new G4DynamicParticle(G4Electron::Definition(), zero);
 88   fSubStepTrack = new G4Track(fSubStepDynamicP     85   fSubStepTrack = new G4Track(fSubStepDynamicParticle, 0, zero);
 89   fSubStep = new G4Step;                       <<  86   fSubStep      = new G4Step;
 90   fSubStepTrack->SetStep(fSubStep);                87   fSubStepTrack->SetStep(fSubStep);
 91 }                                                  88 }
 92                                                    89 
 93 //....oooOO0OOooo........oooOO0OOooo........oo     90 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
 94                                                    91 
 95 G4TransportationWithMsc::~G4TransportationWith     92 G4TransportationWithMsc::~G4TransportationWithMsc()
 96 {                                                  93 {
 97   delete fModelManager;                            94   delete fModelManager;
 98   delete fParticleChangeForMSC;                    95   delete fParticleChangeForMSC;
 99   delete fEmData;                              << 
100   delete fParticleChangeForSS;                 << 
101   delete fSecondariesSS;                       << 
102                                                    96 
103   // fSubStepDynamicParticle is owned and also     97   // fSubStepDynamicParticle is owned and also deleted by fSubStepTrack!
104   delete fSubStepTrack;                            98   delete fSubStepTrack;
105   delete fSubStep;                                 99   delete fSubStep;
106 }                                                 100 }
107                                                   101 
108 //....oooOO0OOooo........oooOO0OOooo........oo    102 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
109                                                   103 
110 void G4TransportationWithMsc::AddMscModel(G4VM    104 void G4TransportationWithMsc::AddMscModel(G4VMscModel* mscModel, G4int order,
111                                           cons    105                                           const G4Region* region)
112 {                                                 106 {
113   if (fType != ScatteringType::MultipleScatter << 107   if(fType != ScatteringType::MultipleScattering)
114     G4Exception("G4TransportationWithMsc::AddM << 108   {
                                                   >> 109     G4Exception("G4TransportationWithMsc::AddMscModel", "em0051",
                                                   >> 110                 FatalException,
115                 "not allowed unless type == Mu    111                 "not allowed unless type == MultipleScattering");
116   }                                               112   }
117                                                   113 
118   fModelManager->AddEmModel(order, mscModel, n    114   fModelManager->AddEmModel(order, mscModel, nullptr, region);
119   mscModel->SetParticleChange(fParticleChangeF    115   mscModel->SetParticleChange(fParticleChangeForMSC);
120 }                                                 116 }
121                                                   117 
122 //....oooOO0OOooo........oooOO0OOooo........oo    118 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
123                                                   119 
124 void G4TransportationWithMsc::AddSSModel(G4VEm << 120 void G4TransportationWithMsc::PreparePhysicsTable(
                                                   >> 121   const G4ParticleDefinition& part)
125 {                                                 122 {
126   if (fType != ScatteringType::SingleScatterin << 123   if(nullptr == fFirstParticle)
127     G4Exception("G4TransportationWithMsc::AddS << 124   {
128                 "not allowed unless type == Si << 
129   }                                            << 
130                                                << 
131   fModelManager->AddEmModel(order, model, null << 
132   model->SetPolarAngleLimit(0.0);              << 
133   model->SetParticleChange(fParticleChangeForS << 
134 }                                              << 
135                                                << 
136 //....oooOO0OOooo........oooOO0OOooo........oo << 
137                                                << 
138 void G4TransportationWithMsc::PreparePhysicsTa << 
139 {                                              << 
140   if (nullptr == fFirstParticle) {             << 
141     fFirstParticle = &part;                       125     fFirstParticle = &part;
142     G4VMultipleScattering* ptr = nullptr;         126     G4VMultipleScattering* ptr = nullptr;
143     auto emConfigurator = fEmManager->EmConfig    127     auto emConfigurator = fEmManager->EmConfigurator();
144     emConfigurator->PrepareModels(&part, ptr,     128     emConfigurator->PrepareModels(&part, ptr, this);
145   }                                               129   }
146                                                   130 
147   if (fFirstParticle == &part) {               << 131   if(fFirstParticle == &part)
148     G4bool master = fEmManager->IsMaster();    << 132   {
149     G4LossTableBuilder* bld = fEmManager->GetT << 133     G4bool master             = fEmManager->IsMaster();
150     G4bool baseMat = bld->GetBaseMaterialFlag( << 134     G4LossTableBuilder* bld   = fEmManager->GetTableBuilder();
                                                   >> 135     G4bool baseMat            = bld->GetBaseMaterialFlag();
151     const auto* theParameters = G4EmParameters    136     const auto* theParameters = G4EmParameters::Instance();
152                                                   137 
153     if (master) {                              << 138     if(master)
                                                   >> 139     {
154       SetVerboseLevel(theParameters->Verbose()    140       SetVerboseLevel(theParameters->Verbose());
155     }                                             141     }
156     else {                                     << 142     else
                                                   >> 143     {
157       SetVerboseLevel(theParameters->WorkerVer    144       SetVerboseLevel(theParameters->WorkerVerbose());
158     }                                             145     }
159                                                   146 
160     const G4int numberOfModels = fModelManager    147     const G4int numberOfModels = fModelManager->NumberOfModels();
161     if (fType == ScatteringType::MultipleScatt << 148     if(fType == ScatteringType::MultipleScattering)
162       for (G4int i = 0; i < numberOfModels; ++ << 149     {
                                                   >> 150       for(G4int i = 0; i < numberOfModels; ++i)
                                                   >> 151       {
163         auto msc = static_cast<G4VMscModel*>(f    152         auto msc = static_cast<G4VMscModel*>(fModelManager->GetModel(i));
                                                   >> 153         msc->SetMasterThread(master);
164         msc->SetPolarAngleLimit(theParameters-    154         msc->SetPolarAngleLimit(theParameters->MscThetaLimit());
165         G4double emax = std::min(msc->HighEner << 155         G4double emax =
                                                   >> 156           std::min(msc->HighEnergyLimit(), theParameters->MaxKinEnergy());
166         msc->SetHighEnergyLimit(emax);            157         msc->SetHighEnergyLimit(emax);
167         msc->SetUseBaseMaterials(baseMat);        158         msc->SetUseBaseMaterials(baseMat);
168       }                                           159       }
169     }                                             160     }
170     else if (fType == ScatteringType::SingleSc << 
171       if (master) {                            << 
172         if (fEmData == nullptr) {              << 
173           fEmData = new G4EmDataHandler(2);    << 
174         }                                      << 
175                                                   161 
176         fLambdaTable = fEmData->MakeTable(0);  << 162     fModelManager->Initialise(fFirstParticle, G4Electron::Electron(),
177         bld->InitialiseBaseMaterials(fLambdaTa << 163                               verboseLevel);
178       }                                        << 
179     }                                          << 
180                                                << 
181     fCuts = fModelManager->Initialise(fFirstPa << 
182   }                                               164   }
183 }                                                 165 }
184                                                   166 
185 //....oooOO0OOooo........oooOO0OOooo........oo    167 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
186                                                   168 
187 void G4TransportationWithMsc::BuildPhysicsTabl << 169 void G4TransportationWithMsc::BuildPhysicsTable(
                                                   >> 170   const G4ParticleDefinition& part)
188 {                                                 171 {
189   if (fFirstParticle == &part) {               << 172   if(fFirstParticle == &part)
                                                   >> 173   {
190     fEmManager->BuildPhysicsTable(fFirstPartic    174     fEmManager->BuildPhysicsTable(fFirstParticle);
191                                                   175 
192     if (fEmManager->IsMaster()) {              << 176     if(!fEmManager->IsMaster())
193       if (fType == ScatteringType::SingleScatt << 177     {
194         const auto* theParameters = G4EmParame << 178       const auto masterProcess =
195         G4LossTableBuilder* bld = fEmManager-> << 179         static_cast<const G4TransportationWithMsc*>(GetMasterProcess());
196         const G4ProductionCutsTable* theCouple << 
197           G4ProductionCutsTable::GetProduction << 
198         std::size_t numOfCouples = theCoupleTa << 
199                                                << 
200         G4double emin = theParameters->MinKinE << 
201         G4double emax = theParameters->MaxKinE << 
202                                                << 
203         G4double scale = emax / emin;          << 
204         G4int nbin = theParameters->NumberOfBi << 
205         scale = nbin / G4Log(scale);           << 
206                                                << 
207         G4int bin = G4lrint(scale * G4Log(emax << 
208         bin = std::max(bin, 5);                << 
209                                                << 
210         for (std::size_t i = 0; i < numOfCoupl << 
211           if (!bld->GetFlag(i)) continue;      << 
212                                                << 
213           // Create physics vector and fill it << 
214           const G4MaterialCutsCouple* couple = << 
215                                                << 
216           auto* aVector = new G4PhysicsLogVect << 
217           fModelManager->FillLambdaVector(aVec << 
218           aVector->FillSecondDerivatives();    << 
219           G4PhysicsTableHelper::SetPhysicsVect << 
220         }                                      << 
221       }                                        << 
222     }                                          << 
223     else {                                     << 
224       const auto masterProcess = static_cast<c << 
225                                                   180 
226       // Initialisation of models.                181       // Initialisation of models.
227       const G4int numberOfModels = fModelManag    182       const G4int numberOfModels = fModelManager->NumberOfModels();
228       if (fType == ScatteringType::MultipleSca << 183       if(fType == ScatteringType::MultipleScattering)
229         for (G4int i = 0; i < numberOfModels;  << 184       {
                                                   >> 185         for(G4int i = 0; i < numberOfModels; ++i)
                                                   >> 186         {
230           auto msc = static_cast<G4VMscModel*>    187           auto msc = static_cast<G4VMscModel*>(fModelManager->GetModel(i));
231           auto msc0 = static_cast<G4VMscModel* << 188           auto msc0 =
                                                   >> 189             static_cast<G4VMscModel*>(masterProcess->fModelManager->GetModel(i));
232           msc->SetCrossSectionTable(msc0->GetC    190           msc->SetCrossSectionTable(msc0->GetCrossSectionTable(), false);
233           msc->InitialiseLocal(fFirstParticle,    191           msc->InitialiseLocal(fFirstParticle, msc0);
234         }                                         192         }
235       }                                           193       }
236       else if (fType == ScatteringType::Single << 
237         this->fLambdaTable = masterProcess->fL << 
238       }                                        << 
239     }                                             194     }
240   }                                               195   }
241                                                   196 
242   if (!G4EmParameters::Instance()->IsPrintLock << 197   if(!G4EmParameters::Instance()->IsPrintLocked() && verboseLevel > 0)
                                                   >> 198   {
243     G4cout << G4endl;                             199     G4cout << G4endl;
244     G4cout << GetProcessName() << ": for " <<     200     G4cout << GetProcessName() << ": for " << part.GetParticleName();
245     if (fMultipleSteps) {                      << 201     if(fMultipleSteps)
                                                   >> 202     {
246       G4cout << " (multipleSteps: 1)";            203       G4cout << " (multipleSteps: 1)";
247     }                                             204     }
248     G4cout << G4endl;                             205     G4cout << G4endl;
249     fModelManager->DumpModelList(G4cout, verbo    206     fModelManager->DumpModelList(G4cout, verboseLevel);
250   }                                               207   }
251 }                                                 208 }
252                                                   209 
253 //....oooOO0OOooo........oooOO0OOooo........oo    210 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
254                                                   211 
255 void G4TransportationWithMsc::StartTracking(G4    212 void G4TransportationWithMsc::StartTracking(G4Track* track)
256 {                                                 213 {
257   auto* currParticle = track->GetParticleDefin    214   auto* currParticle = track->GetParticleDefinition();
258   fIonisation = fEmManager->GetEnergyLossProce << 215   auto* ionisation   = fEmManager->GetEnergyLossProcess(currParticle);
259                                                   216 
260   fSubStepDynamicParticle->SetDefinition(currP    217   fSubStepDynamicParticle->SetDefinition(currParticle);
261                                                   218 
262   const G4int numberOfModels = fModelManager->    219   const G4int numberOfModels = fModelManager->NumberOfModels();
263   if (fType == ScatteringType::MultipleScatter << 220   if(fType == ScatteringType::MultipleScattering)
264     for (G4int i = 0; i < numberOfModels; ++i) << 221   {
                                                   >> 222     for(G4int i = 0; i < numberOfModels; ++i)
                                                   >> 223     {
265       auto msc = static_cast<G4VMscModel*>(fMo    224       auto msc = static_cast<G4VMscModel*>(fModelManager->GetModel(i));
266       msc->StartTracking(track);                  225       msc->StartTracking(track);
267       msc->SetIonisation(fIonisation, currPart << 226       msc->SetIonisation(ionisation, currParticle);
268     }                                             227     }
269   }                                               228   }
270                                                   229 
271   // Ensure that field propagation state is al    230   // Ensure that field propagation state is also cleared / prepared
272   G4Transportation::StartTracking(track);         231   G4Transportation::StartTracking(track);
273 }                                                 232 }
274                                                   233 
275 //....oooOO0OOooo........oooOO0OOooo........oo    234 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
276                                                   235 
277 G4double G4TransportationWithMsc::AlongStepGet << 236 G4double G4TransportationWithMsc::AlongStepGetPhysicalInteractionLength(
278                                                << 237   const G4Track& track, G4double previousStepSize, G4double currentMinimumStep,
279                                                << 238   G4double& proposedSafety, G4GPILSelection* selection)
280                                                << 
281                                                << 
282 {                                                 239 {
283   *selection = NotCandidateForSelection;          240   *selection = NotCandidateForSelection;
284                                                   241 
285   const G4double physStepLimit = currentMinimu    242   const G4double physStepLimit = currentMinimumStep;
286                                                   243 
287   switch (fType) {                             << 244   switch(fType)
                                                   >> 245   {
288     case ScatteringType::MultipleScattering: {    246     case ScatteringType::MultipleScattering: {
289       // Select the MSC model for the current     247       // Select the MSC model for the current kinetic energy.
290       G4VMscModel* mscModel = nullptr;         << 248       G4VMscModel* mscModel          = nullptr;
291       const G4double ekin = track.GetKineticEn << 249       const G4double ekin            = track.GetKineticEnergy();
292       const auto* couple = track.GetMaterialCu << 250       const auto* couple             = track.GetMaterialCutsCouple();
293       const auto* particleDefinition = track.G    251       const auto* particleDefinition = track.GetParticleDefinition();
294       if (physStepLimit > kGeomMin) {          << 252       if(physStepLimit > kGeomMin)
                                                   >> 253       {
295         G4double ekinForSelection = ekin;         254         G4double ekinForSelection = ekin;
296         G4double pdgMass = particleDefinition- << 255         G4double pdgMass          = particleDefinition->GetPDGMass();
297         if (pdgMass > CLHEP::GeV) {            << 256         if(pdgMass > CLHEP::GeV)
                                                   >> 257         {
298           ekinForSelection *= proton_mass_c2 /    258           ekinForSelection *= proton_mass_c2 / pdgMass;
299         }                                         259         }
300                                                   260 
301         if (ekinForSelection >= kLowestKinEner << 261         if(ekinForSelection >= kLowestKinEnergy)
                                                   >> 262         {
302           mscModel = static_cast<G4VMscModel*>    263           mscModel = static_cast<G4VMscModel*>(
303             fModelManager->SelectModel(ekinFor    264             fModelManager->SelectModel(ekinForSelection, couple->GetIndex()));
304           if (mscModel == nullptr) {           << 265           if(mscModel == nullptr)
305             G4Exception("G4TransportationWithM << 266           {
306                         "no MSC model found"); << 267             G4Exception("G4TransportationWithMsc::AlongStepGPIL", "em0052",
                                                   >> 268                         FatalException, "no MSC model found");
307           }                                       269           }
308           if (!mscModel->IsActive(ekinForSelec << 270           if(!mscModel->IsActive(ekinForSelection))
                                                   >> 271           {
309             mscModel = nullptr;                   272             mscModel = nullptr;
310           }                                       273           }
311         }                                         274         }
312       }                                           275       }
313                                                   276 
314       // Call the MSC model to potentially lim    277       // Call the MSC model to potentially limit the step and convert to
315       // geometric path length.                   278       // geometric path length.
316       if (mscModel != nullptr) {               << 279       if(mscModel != nullptr)
                                                   >> 280       {
317         mscModel->SetCurrentCouple(couple);       281         mscModel->SetCurrentCouple(couple);
318                                                   282 
319         // Use the provided track for the firs    283         // Use the provided track for the first step.
320         const G4Track* currentTrackPtr = &trac    284         const G4Track* currentTrackPtr = &track;
321                                                   285 
322         G4double currentSafety = proposedSafet    286         G4double currentSafety = proposedSafety;
323         G4double currentEnergy = ekin;            287         G4double currentEnergy = ekin;
324                                                   288 
325         G4double stepLimitLeft = physStepLimit << 289         G4double stepLimitLeft           = physStepLimit;
326         G4double totalGeometryStepLength = 0,     290         G4double totalGeometryStepLength = 0, totalTruePathLength = 0;
327         G4bool firstStep = true, continueStepp    291         G4bool firstStep = true, continueStepping = fMultipleSteps;
328                                                   292 
329         do {                                   << 293         do
                                                   >> 294         {
330           G4double gPathLength = stepLimitLeft    295           G4double gPathLength = stepLimitLeft;
331           G4double tPathLength =                  296           G4double tPathLength =
332             mscModel->ComputeTruePathLengthLim    297             mscModel->ComputeTruePathLengthLimit(*currentTrackPtr, gPathLength);
333           G4bool mscLimitsStep = (tPathLength     298           G4bool mscLimitsStep = (tPathLength < stepLimitLeft);
334           if (!fMultipleSteps && mscLimitsStep << 299           if(!fMultipleSteps && mscLimitsStep)
                                                   >> 300           {
335             // MSC limits the step.               301             // MSC limits the step.
336             *selection = CandidateForSelection    302             *selection = CandidateForSelection;
337           }                                       303           }
338                                                   304 
339           if (!firstStep) {                    << 305           if(!firstStep)
                                                   >> 306           {
340             // Move the navigator to where the    307             // Move the navigator to where the previous step ended.
341             fLinearNavigator->LocateGlobalPoin << 308             fLinearNavigator->LocateGlobalPointWithinVolume(
                                                   >> 309               fTransportEndPosition);
342           }                                       310           }
343                                                   311 
344           G4GPILSelection transportSelection;     312           G4GPILSelection transportSelection;
345           G4double geometryStepLength = G4Tran << 313           G4double geometryStepLength =
346             *currentTrackPtr, previousStepSize << 314             G4Transportation::AlongStepGetPhysicalInteractionLength(
347           if (geometryStepLength < gPathLength << 315               *currentTrackPtr, previousStepSize, gPathLength, currentSafety,
                                                   >> 316               &transportSelection);
                                                   >> 317           if(geometryStepLength < gPathLength)
                                                   >> 318           {
348             // Transportation limits the step,    319             // Transportation limits the step, ie the track hit a boundary.
349             *selection = CandidateForSelection << 320             *selection       = CandidateForSelection;
350             continueStepping = false;             321             continueStepping = false;
351           }                                       322           }
352           if (fTransportEndKineticEnergy != cu << 323           if(fTransportEndKineticEnergy != currentEnergy)
                                                   >> 324           {
353             // Field propagation changed the e    325             // Field propagation changed the energy, it's not possible to
354             // estimate the continuous energy     326             // estimate the continuous energy loss and continue stepping.
355             continueStepping = false;             327             continueStepping = false;
356           }                                       328           }
357                                                   329 
358           if (firstStep) {                     << 330           if(firstStep)
                                                   >> 331           {
359             proposedSafety = currentSafety;       332             proposedSafety = currentSafety;
360           }                                       333           }
361           totalGeometryStepLength += geometryS    334           totalGeometryStepLength += geometryStepLength;
362                                                   335 
363           // Sample MSC direction change and d    336           // Sample MSC direction change and displacement.
364           const G4double range = mscModel->Get << 337           const G4double range =
                                                   >> 338             mscModel->GetRange(particleDefinition, currentEnergy, couple);
365                                                   339 
366           tPathLength = mscModel->ComputeTrueS    340           tPathLength = mscModel->ComputeTrueStepLength(geometryStepLength);
367                                                   341 
368           // Protect against wrong t->g->t con    342           // Protect against wrong t->g->t conversion.
369           tPathLength = std::min(tPathLength,     343           tPathLength = std::min(tPathLength, stepLimitLeft);
370                                                   344 
371           totalTruePathLength += tPathLength;     345           totalTruePathLength += tPathLength;
372           if (*selection != CandidateForSelect << 346           if(*selection != CandidateForSelection && !mscLimitsStep)
                                                   >> 347           {
373             // If neither MSC nor transportati    348             // If neither MSC nor transportation limits the step, we got the
374             // distance we want - make sure we    349             // distance we want - make sure we exit the loop.
375             continueStepping = false;             350             continueStepping = false;
376           }                                       351           }
377           else if (tPathLength >= range) {     << 352           else if(tPathLength >= range)
                                                   >> 353           {
378             // The particle will stop, exit th    354             // The particle will stop, exit the loop.
379             continueStepping = false;             355             continueStepping = false;
380           }                                       356           }
381           else {                               << 357           else
                                                   >> 358           {
382             stepLimitLeft -= tPathLength;         359             stepLimitLeft -= tPathLength;
383           }                                       360           }
384                                                   361 
385           // Do not sample scattering at the l    362           // Do not sample scattering at the last or at a small step.
386           if (tPathLength < range && tPathLeng << 363           if(tPathLength < range && tPathLength > kGeomMin)
                                                   >> 364           {
387             static constexpr G4double minSafet    365             static constexpr G4double minSafety = 1.20 * CLHEP::nm;
388             static constexpr G4double sFact =  << 366             static constexpr G4double sFact     = 0.99;
389                                                   367 
390             // The call to SampleScattering()     368             // The call to SampleScattering() *may* directly fill in the changed
391             // direction into fParticleChangeF    369             // direction into fParticleChangeForMSC, so we have to:
392             // 1) Make sure the momentum direc    370             // 1) Make sure the momentum direction is initialized.
393             fParticleChangeForMSC->ProposeMome    371             fParticleChangeForMSC->ProposeMomentumDirection(fTransportEndMomentumDir);
394             // 2) Call SampleScattering(), whi    372             // 2) Call SampleScattering(), which *may* change it.
395             const G4ThreeVector displacement =    373             const G4ThreeVector displacement =
396               mscModel->SampleScattering(fTran    374               mscModel->SampleScattering(fTransportEndMomentumDir, minSafety);
397             // 3) Get the changed direction.      375             // 3) Get the changed direction.
398             fTransportEndMomentumDir = *fParti    376             fTransportEndMomentumDir = *fParticleChangeForMSC->GetProposedMomentumDirection();
399                                                   377 
400             const G4double r2 = displacement.m    378             const G4double r2 = displacement.mag2();
401             if (r2 > kMinDisplacement2) {      << 379             if(r2 > kMinDisplacement2)
                                                   >> 380             {
402               G4bool positionChanged = true;      381               G4bool positionChanged = true;
403               G4double dispR = std::sqrt(r2);  << 382               G4double dispR         = std::sqrt(r2);
404               G4double postSafety =            << 383               G4double postSafety    = sFact * fpSafetyHelper->ComputeSafety(
405                 sFact * fpSafetyHelper->Comput << 384                                                  fTransportEndPosition, dispR);
406                                                   385 
407               // Far away from geometry bounda    386               // Far away from geometry boundary
408               if (postSafety > 0.0 && dispR <= << 387               if(postSafety > 0.0 && dispR <= postSafety)
                                                   >> 388               {
409                 fTransportEndPosition += displ    389                 fTransportEndPosition += displacement;
410                                                   390 
411                 // Near the boundary              391                 // Near the boundary
412               }                                   392               }
413               else {                           << 393               else
                                                   >> 394               {
414                 // displaced point is definite    395                 // displaced point is definitely within the volume
415                 if (dispR < postSafety) {      << 396                 if(dispR < postSafety)
                                                   >> 397                 {
416                   fTransportEndPosition += dis    398                   fTransportEndPosition += displacement;
417                                                   399 
418                   // reduced displacement         400                   // reduced displacement
419                 }                                 401                 }
420                 else if (postSafety > kGeomMin << 402                 else if(postSafety > kGeomMin)
                                                   >> 403                 {
421                   fTransportEndPosition += dis    404                   fTransportEndPosition += displacement * (postSafety / dispR);
422                                                   405 
423                   // very small postSafety        406                   // very small postSafety
424                 }                                 407                 }
425                 else {                         << 408                 else
                                                   >> 409                 {
426                   positionChanged = false;        410                   positionChanged = false;
427                 }                                 411                 }
428               }                                   412               }
429               if (positionChanged) {           << 413               if(positionChanged)
                                                   >> 414               {
430                 fpSafetyHelper->ReLocateWithin    415                 fpSafetyHelper->ReLocateWithinVolume(fTransportEndPosition);
431               }                                   416               }
432             }                                     417             }
433           }                                       418           }
434                                                   419 
435           if (continueStepping) {              << 420           if(continueStepping)
                                                   >> 421           {
436             // Update safety according to the     422             // Update safety according to the geometry distance.
437             if (currentSafety < fEndPointDista << 423             if(currentSafety < fEndPointDistance)
                                                   >> 424             {
438               currentSafety = 0;                  425               currentSafety = 0;
439             }                                     426             }
440             else {                             << 427             else
                                                   >> 428             {
441               currentSafety -= fEndPointDistan    429               currentSafety -= fEndPointDistance;
442             }                                     430             }
443                                                   431 
444             // Update the kinetic energy accor    432             // Update the kinetic energy according to the continuous loss.
445             currentEnergy = mscModel->GetEnerg << 433             currentEnergy = mscModel->GetEnergy(particleDefinition,
                                                   >> 434                                                 range - tPathLength, couple);
446                                                   435 
447             // From now on, use the track that    436             // From now on, use the track that we can update below.
448             currentTrackPtr = fSubStepTrack;      437             currentTrackPtr = fSubStepTrack;
449                                                   438 
450             fSubStepDynamicParticle->SetKineti    439             fSubStepDynamicParticle->SetKineticEnergy(currentEnergy);
451             fSubStepDynamicParticle->SetMoment << 440             fSubStepDynamicParticle->SetMomentumDirection(
                                                   >> 441               fTransportEndMomentumDir);
452             fSubStepTrack->SetPosition(fTransp    442             fSubStepTrack->SetPosition(fTransportEndPosition);
453                                                   443 
454             G4StepPoint& subPreStepPoint = *fS    444             G4StepPoint& subPreStepPoint = *fSubStep->GetPreStepPoint();
455             subPreStepPoint.SetMaterialCutsCou    445             subPreStepPoint.SetMaterialCutsCouple(couple);
456             subPreStepPoint.SetPosition(fTrans    446             subPreStepPoint.SetPosition(fTransportEndPosition);
457             subPreStepPoint.SetSafety(currentS    447             subPreStepPoint.SetSafety(currentSafety);
458             subPreStepPoint.SetStepStatus(fAlo    448             subPreStepPoint.SetStepStatus(fAlongStepDoItProc);
459           }                                       449           }
460           firstStep = false;                      450           firstStep = false;
461         } while (continueStepping);            << 451         } while(continueStepping);
462                                                   452 
463         // Note: currentEnergy is only updated    453         // Note: currentEnergy is only updated if continueStepping is true.
464         // In case field propagation changed t    454         // In case field propagation changed the energy, this flag is
465         // immediately set to false and curren    455         // immediately set to false and currentEnergy is still equal to the
466         // initial kinetic energy stored in ek    456         // initial kinetic energy stored in ekin.
467         if (currentEnergy != ekin) {           << 457         if(currentEnergy != ekin)
                                                   >> 458         {
468           // If field propagation didn't chang    459           // If field propagation didn't change the energy and we potentially
469           // did multiple steps, reset the ene    460           // did multiple steps, reset the energy that G4Transportation will
470           // propose to not subtract the energ    461           // propose to not subtract the energy loss twice.
471           fTransportEndKineticEnergy = ekin;      462           fTransportEndKineticEnergy = ekin;
472           // Also ask for the range again with    463           // Also ask for the range again with the initial energy so it is
473           // correctly cached in the G4VEnergy    464           // correctly cached in the G4VEnergyLossProcess.
474           // FIXME: Asking for a range should     465           // FIXME: Asking for a range should never change the cached values!
475           (void)mscModel->GetRange(particleDef << 466           (void) mscModel->GetRange(particleDefinition, ekin, couple);
476         }                                         467         }
477                                                   468 
478         fParticleChange.ProposeTrueStepLength(    469         fParticleChange.ProposeTrueStepLength(totalTruePathLength);
479                                                   470 
480         // Inform G4Transportation that the mo    471         // Inform G4Transportation that the momentum might have changed due
481         // to scattering. We do this unconditi    472         // to scattering. We do this unconditionally to avoid the situation
482         // where the last step is done without    473         // where the last step is done without MSC and G4Transportation reset
483         // the flag, for example when running     474         // the flag, for example when running without field.
484         fMomentumChanged = true;                  475         fMomentumChanged = true;
485                                                   476 
486         return totalGeometryStepLength;           477         return totalGeometryStepLength;
487       }                                           478       }
488       break;                                   << 
489     }                                          << 
490                                                << 
491     case ScatteringType::SingleScattering: {   << 
492       // Select the model for the current kine << 
493       const G4double ekin = track.GetKineticEn << 
494       const auto* couple = track.GetMaterialCu << 
495       const auto* particleDefinition = track.G << 
496                                                << 
497       G4double ekinForSelection = ekin;        << 
498       G4double pdgMass = particleDefinition->G << 
499       if (pdgMass > CLHEP::GeV) {              << 
500         ekinForSelection *= proton_mass_c2 / p << 
501       }                                        << 
502                                                << 
503       G4VEmModel* currentModel = fModelManager << 
504       if (currentModel == nullptr) {           << 
505         G4Exception("G4TransportationWithMsc:: << 
506                     "no scattering model found << 
507       }                                        << 
508       if (!currentModel->IsActive(ekinForSelec << 
509         currentModel = nullptr;                << 
510       }                                        << 
511                                                << 
512       if (currentModel != nullptr) {           << 
513         currentModel->SetCurrentCouple(couple) << 
514         G4int coupleIndex = couple->GetIndex() << 
515                                                << 
516         // Compute mean free path.             << 
517         G4double logEkin = track.GetDynamicPar << 
518         G4double lambda = ((*fLambdaTable)[cou << 
519         if (lambda > 0.0) {                    << 
520           // Assume that the mean free path an << 
521           // step, which is a valid approximat << 
522           G4double meanFreePath = 1.0 / lambda << 
523           G4double dedx = fIonisation->GetDEDX << 
524                                                << 
525           G4double currentSafety = proposedSaf << 
526           G4double currentEnergy = ekin;       << 
527                                                << 
528           // Use the provided track for the fi << 
529           const G4Track* currentTrackPtr = &tr << 
530                                                << 
531           G4double stepLimitLeft = physStepLim << 
532           G4double totalStepLength = 0;        << 
533           G4bool firstStep = true, continueSte << 
534                                                << 
535           do {                                 << 
536             G4double interactionLength = meanF << 
537                                                << 
538             G4bool ssLimitsStep = (interaction << 
539             G4double gPathLength = stepLimitLe << 
540             if (ssLimitsStep) {                << 
541               if (!fMultipleSteps) {           << 
542                 // Scattering limits the step. << 
543                 *selection = CandidateForSelec << 
544               }                                << 
545               gPathLength = interactionLength; << 
546             }                                  << 
547                                                << 
548             if (!firstStep) {                  << 
549               // Move the navigator to where t << 
550               fLinearNavigator->LocateGlobalPo << 
551             }                                  << 
552                                                << 
553             G4GPILSelection transportSelection << 
554             G4double geometryStepLength = G4Tr << 
555               *currentTrackPtr, previousStepSi << 
556             if (geometryStepLength < gPathLeng << 
557               // Transportation limits the ste << 
558               *selection = CandidateForSelecti << 
559               ssLimitsStep = false;            << 
560               continueStepping = false;        << 
561             }                                  << 
562             if (fTransportEndKineticEnergy !=  << 
563               // Field propagation changed the << 
564               // estimate the continuous energ << 
565               continueStepping = false;        << 
566             }                                  << 
567                                                << 
568             if (firstStep) {                   << 
569               proposedSafety = currentSafety;  << 
570             }                                  << 
571             totalStepLength += geometryStepLen << 
572                                                << 
573             if (*selection != CandidateForSele << 
574               // If neither scattering nor tra << 
575               // got the distance we want - ma << 
576               continueStepping = false;        << 
577             }                                  << 
578             else {                             << 
579               stepLimitLeft -= geometryStepLen << 
580             }                                  << 
581                                                << 
582             // Update the kinetic energy accor << 
583             G4double energyAfterLinearLoss =   << 
584               fTransportEndKineticEnergy - geo << 
585                                                << 
586             if (ssLimitsStep) {                << 
587               fSubStepDynamicParticle->SetKine << 
588                                                << 
589               // The call to SampleSecondaries << 
590               // direction into fParticleChang << 
591               // 1) Set the momentum direction << 
592               fSubStepDynamicParticle->SetMome << 
593               // 2) Call SampleSecondaries(),  << 
594               currentModel->SampleSecondaries( << 
595                                                << 
596               // 3) Get the changed direction. << 
597               fTransportEndMomentumDir = fPart << 
598                                                << 
599               // Check that the model neither  << 
600               // a local energy deposit becaus << 
601               // to handle these cases.        << 
602               if (fSecondariesSS->size() > 0)  << 
603                 G4Exception("G4TransportationW << 
604                             "scattering model  << 
605               }                                << 
606               if (fParticleChangeForSS->GetLoc << 
607                 G4Exception("G4TransportationW << 
608                             "scattering model  << 
609               }                                << 
610             }                                  << 
611                                                << 
612             if (continueStepping) {            << 
613               // Update safety according to th << 
614               if (currentSafety < fEndPointDis << 
615                 currentSafety = 0;             << 
616               }                                << 
617               else {                           << 
618                 currentSafety -= fEndPointDist << 
619               }                                << 
620                                                << 
621               // Update the energy taking cont << 
622               currentEnergy = energyAfterLinea << 
623                                                << 
624               // From now on, use the track th << 
625               currentTrackPtr = fSubStepTrack; << 
626                                                << 
627               fSubStepDynamicParticle->SetKine << 
628               fSubStepDynamicParticle->SetMome << 
629               fSubStepTrack->SetPosition(fTran << 
630                                                << 
631               G4StepPoint& subPreStepPoint = * << 
632               subPreStepPoint.SetMaterialCutsC << 
633               subPreStepPoint.SetPosition(fTra << 
634               subPreStepPoint.SetSafety(curren << 
635               subPreStepPoint.SetStepStatus(fA << 
636             }                                  << 
637             firstStep = false;                 << 
638           } while (continueStepping);          << 
639                                                << 
640           // Note: currentEnergy is only updat << 
641           // In case field propagation changed << 
642           // immediately set to false and curr << 
643           // initial kinetic energy stored in  << 
644           if (currentEnergy != ekin) {         << 
645             // If field propagation didn't cha << 
646             // did multiple steps, reset the e << 
647             // propose to not subtract the ene << 
648             fTransportEndKineticEnergy = ekin; << 
649           }                                    << 
650                                                << 
651           fParticleChange.ProposeTrueStepLengt << 
652                                                << 
653           // Inform G4Transportation that the  << 
654           // to scattering, even if there is n << 
655           fMomentumChanged = true;             << 
656                                                << 
657           return totalStepLength;              << 
658         }                                      << 
659       }                                        << 
660       break;                                   << 
661     }                                             479     }
662   }                                               480   }
663                                                   481 
664   // If we get here, no scattering has happene    482   // If we get here, no scattering has happened.
665   return G4Transportation::AlongStepGetPhysica    483   return G4Transportation::AlongStepGetPhysicalInteractionLength(
666     track, previousStepSize, currentMinimumSte    484     track, previousStepSize, currentMinimumStep, proposedSafety, selection);
667 }                                                 485 }
668                                                   486 
669 //....oooOO0OOooo........oooOO0OOooo........oo    487 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
670                                                   488