Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/physics_lists/constructors/electromagnetic/src/G4GammaGeneralProcess.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 ]

  1 //
  2 // ********************************************************************
  3 // * License and Disclaimer                                           *
  4 // *                                                                  *
  5 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
  6 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
  7 // * conditions of the Geant4 Software License,  included in the file *
  8 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
  9 // * include a list of copyright holders.                             *
 10 // *                                                                  *
 11 // * Neither the authors of this software system, nor their employing *
 12 // * institutes,nor the agencies providing financial support for this *
 13 // * work  make  any representation or  warranty, express or implied, *
 14 // * regarding  this  software system or assume any liability for its *
 15 // * use.  Please see the license in the file  LICENSE  and URL above *
 16 // * for the full disclaimer and the limitation of liability.         *
 17 // *                                                                  *
 18 // * This  code  implementation is the result of  the  scientific and *
 19 // * technical work of the GEANT4 collaboration.                      *
 20 // * By using,  copying,  modifying or  distributing the software (or *
 21 // * any work based  on the software)  you  agree  to acknowledge its *
 22 // * use  in  resulting  scientific  publications,  and indicate your *
 23 // * acceptance of all terms of the Geant4 Software license.          *
 24 // ********************************************************************
 25 //
 26 //
 27 // -------------------------------------------------------------------
 28 //
 29 // GEANT4 Class file
 30 //
 31 //
 32 // File name:     G4GammaGeneralProcess
 33 //
 34 // Author:        Vladimir Ivanchenko
 35 //
 36 // Creation date: 19.07.2018
 37 //
 38 // Modifications:
 39 //
 40 // Class Description:
 41 //
 42 
 43 // -------------------------------------------------------------------
 44 //
 45 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
 46 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
 47 
 48 #include "G4GammaGeneralProcess.hh"
 49 #include "G4VDiscreteProcess.hh"
 50 #include "G4PhysicalConstants.hh"
 51 #include "G4SystemOfUnits.hh"
 52 #include "G4ProcessManager.hh"
 53 #include "G4ProductionCutsTable.hh"
 54 #include "G4LossTableBuilder.hh"
 55 #include "G4HadronicProcess.hh"
 56 #include "G4LossTableManager.hh"
 57 #include "G4Step.hh"
 58 #include "G4Track.hh"
 59 #include "G4ParticleDefinition.hh"
 60 #include "G4DataVector.hh"
 61 #include "G4PhysicsTable.hh"
 62 #include "G4PhysicsLogVector.hh"
 63 #include "G4PhysicsLinearVector.hh"
 64 #include "G4VParticleChange.hh"
 65 #include "G4PhysicsTableHelper.hh"
 66 #include "G4EmParameters.hh"
 67 #include "G4EmProcessSubType.hh"
 68 #include "G4Material.hh"
 69 #include "G4MaterialCutsCouple.hh"
 70 #include "G4GammaConversionToMuons.hh"
 71 #include "G4Gamma.hh"
 72 
 73 #include "G4Log.hh"
 74 #include <iostream>
 75 
 76 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
 77 
 78 G4EmDataHandler* G4GammaGeneralProcess::theHandler = nullptr;
 79 G4bool G4GammaGeneralProcess::theT[nTables] =
 80   {true,false,true,true,true,false,true,true,true,
 81    true,true,true,true,true,true};
 82 G4String G4GammaGeneralProcess::nameT[nTables] =
 83   {"0","1","2","3","4","5","6","7","8",
 84    "9","10","11","12","13","14"};
 85 
 86 G4GammaGeneralProcess::G4GammaGeneralProcess(const G4String& pname):
 87   G4VEmProcess(pname, fElectromagnetic),
 88   minPEEnergy(150*CLHEP::keV),
 89   minEEEnergy(2*CLHEP::electron_mass_c2),
 90   minMMEnergy(100*CLHEP::MeV)
 91 {
 92   SetVerboseLevel(1);
 93   SetParticle(G4Gamma::Gamma());
 94   SetProcessSubType(fGammaGeneralProcess);
 95   if (nullptr == theHandler) {
 96     theHandler = new G4EmDataHandler(nTables);
 97   }
 98 }
 99 
100 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
101 
102 G4GammaGeneralProcess::~G4GammaGeneralProcess()
103 {
104   if(isTheMaster) {
105     delete theHandler;
106     theHandler = nullptr;
107   }
108 }
109 
110 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
111 
112 G4bool G4GammaGeneralProcess::IsApplicable(const G4ParticleDefinition&)
113 {
114   return true;
115 }
116 
117 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
118 
119 void G4GammaGeneralProcess::AddEmProcess(G4VEmProcess* ptr)
120 {
121   if(nullptr == ptr) { return; }
122   G4int stype = ptr->GetProcessSubType();
123   if(stype == fRayleigh)                 { theRayleigh = ptr; }
124   else if(stype == fPhotoElectricEffect) { thePhotoElectric = ptr; }
125   else if(stype == fComptonScattering)   { theCompton = ptr; }
126   else if(stype == fGammaConversion)     { theConversionEE = ptr; }
127 }
128 
129 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
130 
131 void G4GammaGeneralProcess::AddMMProcess(G4GammaConversionToMuons* ptr)
132 {
133   theConversionMM = ptr;
134 }
135 
136 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
137 
138 void G4GammaGeneralProcess::AddHadProcess(G4HadronicProcess* ptr)
139 {
140   theGammaNuclear = ptr;
141 }
142 
143 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
144 
145 void G4GammaGeneralProcess::PreparePhysicsTable(const G4ParticleDefinition& part)
146 {
147   SetParticle(&part);
148   preStepLambda = 0.0;
149   idxEnergy = 0;
150   currentCouple = nullptr;
151 
152   G4LossTableManager* man = G4LossTableManager::Instance();
153 
154   // initialise base material for the current run
155   G4LossTableBuilder* bld = man->GetTableBuilder();
156   bld->InitialiseBaseMaterials();
157   baseMat = bld->GetBaseMaterialFlag();
158 
159   if(1 < verboseLevel) {
160     G4cout << "G4GammaGeneralProcess::PreparePhysicsTable() for "
161            << GetProcessName()
162            << " and particle " << part.GetParticleName()
163      << " isMaster: " << isTheMaster << G4endl;
164   }
165 
166   // 3 sub-processes must be always defined
167   if(thePhotoElectric == nullptr || theCompton == nullptr ||
168      theConversionEE == nullptr) {
169     G4ExceptionDescription ed;
170     ed << "### G4GeneralGammaProcess is initialized incorrectly"
171        << "\n Photoelectric: " << thePhotoElectric
172        << "\n Compton: " << theCompton
173        << "\n Conversion: " << theConversionEE;
174     G4Exception("G4GeneralGammaProcess","em0004",
175     FatalException, ed,"");
176     return;
177   }
178 
179   thePhotoElectric->PreparePhysicsTable(part);
180   theCompton->PreparePhysicsTable(part);
181   theConversionEE->PreparePhysicsTable(part);
182   if (nullptr != theRayleigh) { theRayleigh->PreparePhysicsTable(part); }
183   if (nullptr != theGammaNuclear) { theGammaNuclear->PreparePhysicsTable(part); }
184   if (nullptr != theConversionMM) { theConversionMM->PreparePhysicsTable(part); }
185 
186   InitialiseProcess(&part);
187 }
188 
189 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
190 
191 void G4GammaGeneralProcess::InitialiseProcess(const G4ParticleDefinition*)
192 {
193   if(isTheMaster) {
194 
195     G4EmParameters* param = G4EmParameters::Instance();
196     G4LossTableManager* man = G4LossTableManager::Instance();
197 
198     // tables are created and its size is defined only once
199     if (nullptr != theRayleigh) { theT[1] = true; }
200 
201     theHandler->SetMasterProcess(thePhotoElectric);
202     theHandler->SetMasterProcess(theCompton);
203     theHandler->SetMasterProcess(theConversionEE);
204     theHandler->SetMasterProcess(theRayleigh);
205    
206     auto bld = man->GetTableBuilder();
207 
208     const G4ProductionCutsTable* theCoupleTable=
209       G4ProductionCutsTable::GetProductionCutsTable();
210     std::size_t numOfCouples = theCoupleTable->GetTableSize();
211 
212     G4double mine = param->MinKinEnergy();
213     G4double maxe = param->MaxKinEnergy();
214     G4int nd = param->NumberOfBinsPerDecade();
215     std::size_t nbin1 = std::max(5, nd*G4lrint(std::log10(minPEEnergy/mine)));
216     std::size_t nbin2 = std::max(5, nd*G4lrint(std::log10(maxe/minMMEnergy)));
217 
218     G4PhysicsVector* vec = nullptr;
219     G4PhysicsLogVector aVector(mine,minPEEnergy,nbin1,true);
220     G4PhysicsLogVector bVector(minPEEnergy,minEEEnergy,nLowE,false);
221     G4PhysicsLogVector cVector(minEEEnergy,minMMEnergy,nHighE,false);
222     G4PhysicsLogVector dVector(minMMEnergy,maxe,nbin2,true);
223 
224     for(std::size_t i=0; i<nTables; ++i) {
225       if(!theT[i]) { continue; }
226       //G4cout << "## PreparePhysTable " << i << "." << G4endl;
227       G4PhysicsTable* table = theHandler->MakeTable(i);
228       //G4cout << "   make table " << table << G4endl;
229       for(std::size_t j=0; j<numOfCouples; ++j) {
230   vec = (*table)[j];
231   if (bld->GetFlag(j) && nullptr == vec) {
232     if(i<=1) {
233       vec = new G4PhysicsVector(aVector);
234     } else if(i<=5) {
235       vec = new G4PhysicsVector(bVector);
236     } else if(i<=9) {
237       vec = new G4PhysicsVector(cVector);
238     } else {
239       vec = new G4PhysicsVector(dVector);
240     }
241     G4PhysicsTableHelper::SetPhysicsVector(table, j, vec);
242   }
243       }
244     }
245   }
246 }
247 
248 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
249 
250 void G4GammaGeneralProcess::BuildPhysicsTable(const G4ParticleDefinition& part)
251 {
252   if(1 < verboseLevel) {
253     G4cout << "### G4VEmProcess::BuildPhysicsTable() for "
254            << GetProcessName()
255            << " and particle " << part.GetParticleName()
256            << G4endl;
257   }
258   if(!isTheMaster) {
259     thePhotoElectric->SetEmMasterProcess(theHandler->GetMasterProcess(0));
260     baseMat = theHandler->GetMasterProcess(0)->UseBaseMaterial();
261   }
262   thePhotoElectric->BuildPhysicsTable(part);
263 
264   if(!isTheMaster) {
265     theCompton->SetEmMasterProcess(theHandler->GetMasterProcess(1));
266   }
267   theCompton->BuildPhysicsTable(part);
268 
269   if(!isTheMaster) {
270     theConversionEE->SetEmMasterProcess(theHandler->GetMasterProcess(2));
271   }
272   theConversionEE->BuildPhysicsTable(part);
273 
274   if(theRayleigh != nullptr) {
275     if(!isTheMaster) {
276       theRayleigh->SetEmMasterProcess(theHandler->GetMasterProcess(3));
277     }
278     theRayleigh->BuildPhysicsTable(part);
279   }
280   if(theGammaNuclear != nullptr)  { theGammaNuclear->BuildPhysicsTable(part); }
281   if(theConversionMM != nullptr)  { theConversionMM->BuildPhysicsTable(part); }
282 
283   if(isTheMaster) {
284     const G4ProductionCutsTable* theCoupleTable=
285       G4ProductionCutsTable::GetProductionCutsTable();
286     G4int numOfCouples = (G4int)theCoupleTable->GetTableSize();
287 
288     G4LossTableBuilder* bld = G4LossTableManager::Instance()->GetTableBuilder();
289     const std::vector<G4PhysicsTable*>& tables = theHandler->GetTables();
290 
291     G4CrossSectionDataStore* gn = (nullptr != theGammaNuclear)
292       ? theGammaNuclear->GetCrossSectionDataStore() : nullptr;
293     G4DynamicParticle* dynParticle =
294       new G4DynamicParticle(G4Gamma::Gamma(),G4ThreeVector(1,0,0),1.0);
295 
296     G4double sigComp(0.), sigPE(0.), sigConv(0.), sigR(0.),
297       sigN(0.), sigM(0.), val(0.);
298 
299     for(G4int i=0; i<numOfCouples; ++i) {
300 
301       if (bld->GetFlag(i)) {
302         G4int idx = (!baseMat) ? i : DensityIndex(i);
303   const G4MaterialCutsCouple* couple =
304     theCoupleTable->GetMaterialCutsCouple(i);
305   const G4Material* material = couple->GetMaterial();
306 
307   // energy interval 0
308         std::size_t nn = (*(tables[0]))[idx]->GetVectorLength();
309   if(1 < verboseLevel) {
310           G4cout << "======= Zone 0 ======= N= " << nn
311      << " for " << material->GetName() << G4endl;
312   }
313         for(std::size_t j=0; j<nn; ++j) {
314           G4double e = (*(tables[0]))[idx]->Energy(j);
315           G4double loge = G4Log(e);
316           sigComp = theCompton->GetLambda(e, couple, loge);
317           sigR = (nullptr != theRayleigh) ?
318             theRayleigh->GetLambda(e, couple, loge) : 0.0;
319           G4double sum = sigComp + sigR;
320     if(1 < verboseLevel) {
321       G4cout << j << ". E= " << e << " xs= " << sum
322        << " compt= " << sigComp << " Rayl= " << sigR << G4endl;
323     }
324           (*(tables[0]))[idx]->PutValue(j, sum);
325     if(theT[1]) {
326             val = sigR/sum;
327       (*(tables[1]))[idx]->PutValue(j, val);
328     }
329   }
330 
331   // energy interval 1
332         nn = (*(tables[2]))[idx]->GetVectorLength();
333   if(1 < verboseLevel) {
334     G4cout << "======= Zone 1 ======= N= " << nn << G4endl;
335   }
336         for(std::size_t j=0; j<nn; ++j) {
337           G4double e = (*(tables[2]))[idx]->Energy(j);
338           G4double loge = G4Log(e);
339           sigComp = theCompton->GetLambda(e, couple, loge);
340           sigR = (nullptr != theRayleigh) ?
341             theRayleigh->GetLambda(e, couple, loge) : 0.0;
342           sigPE = thePhotoElectric->GetLambda(e, couple, loge);
343           G4double sum = sigComp + sigR + sigPE;
344     if(1 < verboseLevel) {
345       G4cout << j << ". E= " << e << " xs= " << sum
346        << " compt= " << sigComp << " conv= " << sigConv
347        << " PE= " << sigPE << " Rayl= " << sigR
348        << " GN= " << sigN << G4endl;
349     }
350           (*(tables[2]))[idx]->PutValue(j, sum);
351 
352           val = sigPE/sum;
353     (*(tables[3]))[idx]->PutValue(j, val);
354 
355     val = (sigR > 0.0) ? (sigComp + sigPE)/sum : 1.0;
356     (*(tables[4]))[idx]->PutValue(j, val);
357   }
358 
359   // energy interval 2
360         nn = (*(tables[6]))[idx]->GetVectorLength();
361   if(1 < verboseLevel) {
362     G4cout << "======= Zone 2 ======= N= " << nn << G4endl;
363   }
364         for(std::size_t j=0; j<nn; ++j) {
365           G4double e = (*(tables[6]))[idx]->Energy(j);
366           G4double loge = G4Log(e);
367           sigComp = theCompton->GetLambda(e, couple, loge);
368           sigConv = theConversionEE->GetLambda(e, couple, loge);
369           sigPE = thePhotoElectric->GetLambda(e, couple, loge);
370           sigN = 0.0;
371           if(nullptr != gn) {
372       dynParticle->SetKineticEnergy(e);
373       sigN = gn->ComputeCrossSection(dynParticle, material);
374     }
375           G4double sum = sigComp + sigConv + sigPE + sigN;
376     if(1 < verboseLevel) {
377       G4cout << j << ". E= " << e << " xs= " << sum
378        << " compt= " << sigComp << " conv= " << sigConv
379        << " PE= " << sigPE
380        << " GN= " << sigN << G4endl;
381     }
382           (*(tables[6]))[idx]->PutValue(j, sum);
383 
384           val = sigConv/sum;
385     (*(tables[7]))[idx]->PutValue(j, val);
386 
387           val = (sigConv + sigComp)/sum;
388     (*(tables[8]))[idx]->PutValue(j, val);
389 
390     val = (sigN > 0.0) ? (sigConv + sigComp + sigPE)/sum : 1.0;
391     (*(tables[9]))[idx]->PutValue(j, val);
392   }
393 
394   // energy interval 3
395         nn = (*(tables[10]))[idx]->GetVectorLength();
396   if(1 < verboseLevel) {
397     G4cout << "======= Zone 3 ======= N= " << nn
398      << " for " << material->GetName() << G4endl;
399   }
400         for(std::size_t j=0; j<nn; ++j) {
401           G4double e = (*(tables[10]))[idx]->Energy(j);
402           G4double loge = G4Log(e);
403           sigComp = theCompton->GetLambda(e, couple, loge);
404           sigConv = theConversionEE->GetLambda(e, couple, loge);
405           sigPE = thePhotoElectric->GetLambda(e, couple, loge);
406           sigN = 0.0;
407           if(nullptr != gn) {
408       dynParticle->SetKineticEnergy(e);
409       sigN = gn->ComputeCrossSection(dynParticle, material);
410     }
411           sigM = 0.0;
412           if(nullptr != theConversionMM) {
413       val = theConversionMM->ComputeMeanFreePath(e, material);
414       sigM = (val < DBL_MAX) ? 1./val : 0.0;
415     }
416           G4double sum = sigComp + sigConv + sigPE + sigN + sigM;
417     if(1 < verboseLevel) {
418       G4cout << j << ". E= " << e << " xs= " << sum
419        << " compt= " << sigComp << " conv= " << sigConv
420        << " PE= " << sigPE
421        << " GN= " << sigN << G4endl;
422     }
423           (*(tables[10]))[idx]->PutValue(j, sum);
424 
425           val = (sigComp + sigPE + sigN + sigM)/sum;
426     (*(tables[11]))[idx]->PutValue(j, val);
427 
428           val = (sigPE + sigN + sigM)/sum;
429     (*(tables[12]))[idx]->PutValue(j, val);
430 
431     val = (sigN + sigM)/sum;
432     (*(tables[13]))[idx]->PutValue(j, val);
433 
434     val = sigM/sum;
435     (*(tables[14]))[idx]->PutValue(j, val);
436   }
437   for(std::size_t k=0; k<nTables; ++k) {
438     if(theT[k] && (k <= 1 || k >= 10)) {
439       //G4cout <<"BuildPhysTable spline iTable="<<k<<" jCouple="<< idx << G4endl;
440       (*(tables[k]))[idx]->FillSecondDerivatives();
441     }
442   }
443       }
444     }
445     delete dynParticle;
446   }
447 
448   if(1 < verboseLevel) {
449     G4cout << "### G4VEmProcess::BuildPhysicsTable() done for "
450            << GetProcessName()
451            << " and particle " << part.GetParticleName()
452            << G4endl;
453   }
454 }
455 
456 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
457 
458 void G4GammaGeneralProcess::StartTracking(G4Track*)
459 {
460   theNumberOfInteractionLengthLeft = -1.0;
461 }
462 
463 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
464 
465 G4double G4GammaGeneralProcess::PostStepGetPhysicalInteractionLength(
466                              const G4Track& track,
467                              G4double   previousStepSize,
468                              G4ForceCondition* condition)
469 {
470   *condition = NotForced;
471   G4double x = DBL_MAX;
472 
473   G4double energy = track.GetKineticEnergy();
474   const G4MaterialCutsCouple* couple = track.GetMaterialCutsCouple();
475 
476   // compute mean free path
477   G4bool recompute = false;
478   if(couple != currentCouple) {
479     currentCouple = couple;
480     basedCoupleIndex = currentCoupleIndex = couple->GetIndex();
481     currentMaterial = couple->GetMaterial();
482     factor = 1.0;
483     if(baseMat) {
484       basedCoupleIndex = DensityIndex((G4int)currentCoupleIndex);
485       factor = DensityFactor((G4int)currentCoupleIndex);
486     }
487     recompute = true;
488   }
489   if(energy != preStepKinEnergy) {
490     preStepKinEnergy = energy;
491     preStepLogE = track.GetDynamicParticle()->GetLogKineticEnergy();
492     recompute = true;
493   }
494   if(recompute) {
495     preStepLambda = TotalCrossSectionPerVolume();
496 
497     // zero cross section
498     if(preStepLambda <= 0.0) {
499       theNumberOfInteractionLengthLeft = -1.0;
500       currentInteractionLength = DBL_MAX;
501     }
502   }
503 
504   // non-zero cross section
505   if(preStepLambda > 0.0) {
506 
507     if (theNumberOfInteractionLengthLeft < 0.0) {
508 
509       // beggining of tracking (or just after DoIt of this process)
510       theNumberOfInteractionLengthLeft =  -G4Log( G4UniformRand() );
511       theInitialNumberOfInteractionLength = theNumberOfInteractionLengthLeft;
512 
513     } else if(currentInteractionLength < DBL_MAX) {
514 
515       theNumberOfInteractionLengthLeft -=
516         previousStepSize/currentInteractionLength;
517       theNumberOfInteractionLengthLeft =
518         std::max(theNumberOfInteractionLengthLeft, 0.0);
519     }
520 
521     // new mean free path and step limit for the next step
522     currentInteractionLength = 1.0/preStepLambda;
523     x = theNumberOfInteractionLengthLeft * currentInteractionLength;
524   }
525   /*
526   G4cout << "PostStepGetPhysicalInteractionLength: e= " << energy
527    << " idxe= " << idxEnergy << "  xs= " << preStepLambda
528    << " x= " << x << G4endl;
529   */
530   return x;
531 }
532 
533 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
534 
535 G4double G4GammaGeneralProcess::TotalCrossSectionPerVolume()
536 {
537   G4double cross = 0.0;
538   /*
539   G4cout << "#Total: " << preStepKinEnergy << " " << minPEEnergy << " "
540          << minEEEnergy << " " << minMMEnergy<< G4endl;
541   G4cout << " idxE= " << idxEnergy
542    << " idxC= " << currentCoupleIndex << G4endl;
543   */
544   if(preStepKinEnergy < minPEEnergy) {
545     cross = ComputeGeneralLambda(0, 0);
546     //G4cout << "XS1: " << cross << G4endl;
547     peLambda = thePhotoElectric->GetLambda(preStepKinEnergy, currentCouple, preStepLogE);
548     cross += peLambda;
549     //G4cout << "XS2: " << peLambda << G4endl;
550 
551   } else if(preStepKinEnergy < minEEEnergy) {
552     cross = ComputeGeneralLambda(1, 2);
553     //G4cout << "XS3: " << cross << G4endl;
554 
555   } else if(preStepKinEnergy < minMMEnergy) {
556     cross = ComputeGeneralLambda(2, 6);
557     //G4cout << "XS4: " << cross << G4endl;
558 
559   } else {
560     cross = ComputeGeneralLambda(3, 10);
561     //G4cout << "XS5: " << cross << G4endl;
562   }
563   /*  
564   G4cout << "xs= " << cross << " idxE= " << idxEnergy
565    << " idxC= " << currentCoupleIndex
566    << " E= " << preStepKinEnergy << G4endl;
567   */
568   return cross;
569 }
570 
571 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
572 
573 G4VParticleChange* G4GammaGeneralProcess::PostStepDoIt(const G4Track& track,
574                                                        const G4Step& step)
575 {
576   // In all cases clear number of interaction lengths
577   theNumberOfInteractionLengthLeft = -1.0;
578   selectedProc = nullptr;
579   G4double q = G4UniformRand();
580   /*
581   G4cout << "PostStep: preStepLambda= " << preStepLambda
582          << " PE= " << peLambda << " q= " << q << " idxE= " << idxEnergy
583          << G4endl;
584   */
585   switch (idxEnergy) {
586   case 0:
587     if(preStepLambda*q <= peLambda) {
588       SelectEmProcess(step, thePhotoElectric);
589     } else {
590       if(theT[1] && preStepLambda*q < (preStepLambda - peLambda)*GetProbability(1) + peLambda) {
591   SelectEmProcess(step, theRayleigh);
592       } else {
593   SelectEmProcess(step, theCompton);
594       }
595     }
596     break;
597 
598   case 1:
599     if(q <= GetProbability(3)) {
600       SelectEmProcess(step, thePhotoElectric);
601     } else if(q <= GetProbability(4)) {
602       SelectEmProcess(step, theCompton);
603     } else if(theRayleigh) {
604       SelectEmProcess(step, theRayleigh);
605     } else {
606       SelectEmProcess(step, thePhotoElectric);
607     }
608     break;
609 
610   case 2:
611     if(q <= GetProbability(7)) {
612       SelectEmProcess(step, theConversionEE);
613     } else if(q <= GetProbability(8)) {
614       SelectEmProcess(step, theCompton);
615     } else if(q <= GetProbability(9)) {
616       SelectEmProcess(step, thePhotoElectric);
617     } else if(theGammaNuclear) {
618       SelectHadProcess(track, step, theGammaNuclear);
619     } else {
620       SelectEmProcess(step, theConversionEE);
621     }
622     break;
623 
624   case 3:
625     if(q + GetProbability(11) <= 1.0) {
626       SelectEmProcess(step, theConversionEE);
627     } else if(q + GetProbability(12) <= 1.0) {
628       SelectEmProcess(step, theCompton);
629     } else if(q + GetProbability(13) <= 1.0) {
630       SelectEmProcess(step, thePhotoElectric);
631     } else if(theGammaNuclear && q + GetProbability(14) <= 1.0) {
632       SelectHadProcess(track, step, theGammaNuclear);
633     } else if(theConversionMM) {
634       SelectedProcess(step, theConversionMM);
635     } else {
636       SelectEmProcess(step, theConversionEE);
637     }
638     break;
639   }
640   // sample secondaries
641   if(selectedProc != nullptr) {
642     return selectedProc->PostStepDoIt(track, step);
643   }
644   // no interaction - exception case
645   fParticleChange.InitializeForPostStep(track);
646   return &fParticleChange;
647 }
648 
649 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
650 
651 void G4GammaGeneralProcess::SelectHadProcess(const G4Track& track,
652             const G4Step& step, G4HadronicProcess* proc)
653 {
654   SelectedProcess(step, proc);
655   proc->GetCrossSectionDataStore()->ComputeCrossSection(track.GetDynamicParticle(),
656                                                         currentMaterial);
657 }
658 
659 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
660 
661 G4bool G4GammaGeneralProcess::StorePhysicsTable(const G4ParticleDefinition* part,
662                                               const G4String& directory,
663                                               G4bool ascii)
664 {
665   G4bool yes = true;
666   if(!isTheMaster) { return yes; }
667   if(!thePhotoElectric->StorePhysicsTable(part, directory, ascii))
668     { yes = false; }
669   if(!theCompton->StorePhysicsTable(part, directory, ascii))
670     { yes = false; }
671   if(!theConversionEE->StorePhysicsTable(part, directory, ascii))
672     { yes = false; }
673   if(theRayleigh != nullptr &&
674      !theRayleigh->StorePhysicsTable(part, directory, ascii))
675     { yes = false; }
676 
677   for(std::size_t i=0; i<nTables; ++i) {
678     if(theT[i]) {
679       G4String nam = (0==i || 2==i || 6==i || 10==i)
680   ? "LambdaGeneral" + nameT[i] : "ProbGeneral" + nameT[i];
681       G4String fnam =  GetPhysicsTableFileName(part,directory,nam,ascii);
682       if(!theHandler->StorePhysicsTable(i, part, fnam, ascii)) { yes = false; }
683     }
684   }
685   return yes;
686 }
687 
688 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo.....
689 
690 G4bool
691 G4GammaGeneralProcess::RetrievePhysicsTable(const G4ParticleDefinition* part,
692                                             const G4String& directory,
693                                             G4bool ascii)
694 {
695   if (!isTheMaster) { return true; }
696   if(1 < verboseLevel) {
697     G4cout << "G4GammaGeneralProcess::RetrievePhysicsTable() for "
698            << part->GetParticleName() << " and process "
699            << GetProcessName() << G4endl;
700   }
701   G4bool yes = true;
702   if(!thePhotoElectric->RetrievePhysicsTable(part, directory, ascii))
703     { yes = false; }
704   if(!theCompton->RetrievePhysicsTable(part, directory, ascii))
705     { yes = false; }
706   if(!theConversionEE->RetrievePhysicsTable(part, directory, ascii))
707     { yes = false; }
708   if(theRayleigh != nullptr &&
709      !theRayleigh->RetrievePhysicsTable(part, directory, ascii))
710     { yes = false; }
711 
712   for(std::size_t i=0; i<nTables; ++i) {
713     if(theT[i]) {
714       G4String nam = (0==i || 2==i || 6==i || 10==i)
715   ? "LambdaGeneral" + nameT[i] : "ProbGeneral" + nameT[i];
716       G4String fnam = GetPhysicsTableFileName(part,directory,nam,ascii);
717       G4bool spline = (i <= 1 || i >= 10); 
718       if(!theHandler->RetrievePhysicsTable(i, part, fnam, ascii, spline))
719   { yes = false; }
720     }
721   }
722   return yes;
723 }
724 
725 //....Ooooo0ooooo ........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
726 
727 G4double G4GammaGeneralProcess::GetMeanFreePath(const G4Track& track,
728                                               G4double,
729                                               G4ForceCondition* condition)
730 {
731   *condition = NotForced;
732   return MeanFreePath(track);
733 }
734 
735 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
736 
737 void G4GammaGeneralProcess::ProcessDescription(std::ostream& out) const
738 {
739   thePhotoElectric->ProcessDescription(out);
740   theCompton->ProcessDescription(out);
741   theConversionEE->ProcessDescription(out);
742   if(theRayleigh)      { theRayleigh->ProcessDescription(out); }
743   if(theGammaNuclear)  { theGammaNuclear->ProcessDescription(out); }
744   if(theConversionMM)  { theConversionMM->ProcessDescription(out); }
745 }
746 
747 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
748 
749 const G4String& G4GammaGeneralProcess::GetSubProcessName() const
750 {
751   return (selectedProc) ? selectedProc->GetProcessName()
752     : G4VProcess::GetProcessName();
753 }
754 
755 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
756 
757 G4int G4GammaGeneralProcess::GetSubProcessSubType() const
758 {
759   return (selectedProc) ? selectedProc->GetProcessSubType()
760     : fGammaGeneralProcess;
761 }
762 
763 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
764 
765 G4VEmProcess* G4GammaGeneralProcess::GetEmProcess(const G4String& name)
766 {
767   G4VEmProcess* proc = nullptr;
768   if(name == thePhotoElectric->GetProcessName()) {
769     proc = thePhotoElectric;
770   } else if(name == theCompton->GetProcessName()) {
771     proc = theCompton;
772   } else if(name == theConversionEE->GetProcessName()) {
773     proc = theConversionEE;
774   } else if(theRayleigh != nullptr && name == theRayleigh->GetProcessName()) {
775     proc = theRayleigh;
776   }
777   return proc;
778 }
779 
780 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
781 
782 const G4VProcess* G4GammaGeneralProcess::GetCreatorProcess() const
783 {
784   return selectedProc;
785 }
786 
787 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
788