Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/processes/electromagnetic/standard/src/G4PAIPhotData.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
 30 // File name:     G4PAIPhotData.cc
 31 //
 32 // Author:        V.Grichine based on G4PAIModelData MT
 33 //
 34 // Creation date: 07.10.2013
 35 //
 36 // Modifications:
 37 //
 38 
 39 #include "G4PAIPhotData.hh"
 40 #include "G4PAIPhotModel.hh"
 41 
 42 #include "G4SystemOfUnits.hh"
 43 #include "G4PhysicalConstants.hh"
 44 
 45 #include "G4PhysicsLogVector.hh"
 46 #include "G4PhysicsFreeVector.hh"
 47 #include "G4PhysicsTable.hh"
 48 #include "G4MaterialCutsCouple.hh"
 49 #include "G4ProductionCutsTable.hh"
 50 #include "G4SandiaTable.hh"
 51 #include "Randomize.hh"
 52 #include "G4Poisson.hh"
 53 
 54 ////////////////////////////////////////////////////////////////////////
 55 
 56 using namespace std;
 57 
 58 G4PAIPhotData::G4PAIPhotData(G4double tmin, G4double tmax, G4int ver)
 59 { 
 60   const G4int nPerDecade     = 10; 
 61   const G4double lowestTkin  = 50*keV;
 62   const G4double highestTkin = 10*TeV;
 63 
 64   // fPAIxSection.SetVerbose(ver);
 65 
 66   fLowestKineticEnergy  = std::max(tmin, lowestTkin);
 67   fHighestKineticEnergy = tmax;
 68 
 69   if(tmax < 10*fLowestKineticEnergy) 
 70   { 
 71     fHighestKineticEnergy = 10*fLowestKineticEnergy;
 72   } 
 73   else if(tmax > highestTkin) 
 74   {
 75     fHighestKineticEnergy = std::max(highestTkin, 10*fLowestKineticEnergy);
 76   }
 77   fTotBin = (G4int)(nPerDecade*
 78         std::log10(fHighestKineticEnergy/fLowestKineticEnergy));
 79 
 80   fParticleEnergyVector = new G4PhysicsLogVector(fLowestKineticEnergy,
 81              fHighestKineticEnergy,
 82              fTotBin);
 83   if(0 < ver) {
 84     G4cout << "### G4PAIPhotData: Nbins= " << fTotBin
 85      << " Tmin(MeV)= " << fLowestKineticEnergy/MeV
 86      << " Tmax(GeV)= " << fHighestKineticEnergy/GeV 
 87      << "  tmin(keV)= " << tmin/keV << G4endl;
 88   }
 89 }
 90 
 91 ////////////////////////////////////////////////////////////////////////////
 92 
 93 G4PAIPhotData::~G4PAIPhotData()
 94 {
 95   //G4cout << "G4PAIPhotData::~G4PAIPhotData() " << this << G4endl;
 96   std::size_t n = fPAIxscBank.size();
 97   if(0 < n) 
 98   {
 99     for(std::size_t i=0; i<n; ++i) 
100     {
101       if(fPAIxscBank[i]) 
102       {
103   fPAIxscBank[i]->clearAndDestroy();
104   delete fPAIxscBank[i];
105   fPAIxscBank[i] = nullptr;
106       }
107       if(fPAIdEdxBank[i]) 
108       {
109   fPAIdEdxBank[i]->clearAndDestroy();
110   delete fPAIdEdxBank[i];
111   fPAIdEdxBank[i] = nullptr;
112       }
113       delete fdEdxTable[i];
114       delete fdNdxCutTable[i];
115       fdEdxTable[i] = nullptr;
116       fdNdxCutTable[i] = nullptr;
117     }
118   }
119   delete fParticleEnergyVector;
120   fParticleEnergyVector = nullptr;
121   //G4cout << "G4PAIPhotData::~G4PAIPhotData() done for " << this << G4endl;  
122 }
123 
124 ///////////////////////////////////////////////////////////////////////////////
125 
126 void G4PAIPhotData::Initialise(const G4MaterialCutsCouple* couple,
127                                 G4double cut, G4PAIPhotModel* model)
128 {
129   G4ProductionCutsTable* theCoupleTable=
130         G4ProductionCutsTable::GetProductionCutsTable();
131   G4int numOfCouples = (G4int)theCoupleTable->GetTableSize();
132   G4int jMatCC;
133 
134   for (jMatCC = 0; jMatCC < numOfCouples; ++jMatCC )
135   {
136     if( couple == theCoupleTable->GetMaterialCutsCouple(jMatCC) ) break;
137   }
138   if( jMatCC == numOfCouples && jMatCC > 0 ) --jMatCC;
139 
140   const vector<G4double>*  deltaCutInKineticEnergy = theCoupleTable->GetEnergyCutsVector(idxG4ElectronCut);
141   const vector<G4double>*  photonCutInKineticEnergy = theCoupleTable->GetEnergyCutsVector(idxG4GammaCut);
142   G4double deltaCutInKineticEnergyNow  = (*deltaCutInKineticEnergy)[jMatCC];
143   G4double photonCutInKineticEnergyNow = (*photonCutInKineticEnergy)[jMatCC];
144   /*
145   G4cout<<"G4PAIPhotData::Initialise: "<<"cut = "<<cut/keV<<" keV; cutEl = "
146         <<deltaCutInKineticEnergyNow/keV<<" keV; cutPh = "
147   <<photonCutInKineticEnergyNow/keV<<" keV"<<G4endl;
148   */
149   // if( deltaCutInKineticEnergyNow != cut ) deltaCutInKineticEnergyNow = cut; // exception??
150 
151   auto dEdxCutVector =
152     new G4PhysicsLogVector(fLowestKineticEnergy,
153          fHighestKineticEnergy,
154          fTotBin);
155 
156   auto dNdxCutVector =
157     new G4PhysicsLogVector(fLowestKineticEnergy,
158          fHighestKineticEnergy,
159          fTotBin);
160   auto dNdxCutPhotonVector =
161     new G4PhysicsLogVector(fLowestKineticEnergy,
162          fHighestKineticEnergy,
163          fTotBin);
164   auto dNdxCutPlasmonVector =
165     new G4PhysicsLogVector(fLowestKineticEnergy,
166          fHighestKineticEnergy,
167          fTotBin);
168 
169   const G4Material* mat = couple->GetMaterial();     
170   fSandia.Initialize(const_cast<G4Material*>(mat));
171 
172   auto PAItransferTable = new G4PhysicsTable(fTotBin+1);
173   auto PAIphotonTable = new G4PhysicsTable(fTotBin+1);
174   auto PAIplasmonTable = new G4PhysicsTable(fTotBin+1);
175 
176   auto PAIdEdxTable = new G4PhysicsTable(fTotBin+1);
177   auto dEdxMeanVector =
178     new G4PhysicsLogVector(fLowestKineticEnergy,
179          fHighestKineticEnergy,
180          fTotBin);
181 
182   // low energy Sandia interval
183   G4double Tmin = fSandia.GetSandiaMatTablePAI(0,0); 
184 
185   // energy safety
186   const G4double deltaLow = 100.*eV; 
187 
188   for (G4int i = 0; i <= fTotBin; ++i) 
189   {
190     G4double kinEnergy = fParticleEnergyVector->Energy(i);
191     G4double Tmax = model->ComputeMaxEnergy(kinEnergy);
192     G4double tau = kinEnergy/proton_mass_c2;
193     G4double bg2 = tau*( tau + 2. );
194 
195     if ( Tmax < Tmin + deltaLow ) Tmax = Tmin + deltaLow; 
196 
197     fPAIxSection.Initialize( mat, Tmax, bg2, &fSandia);
198 
199     //G4cout << i << ". TransferMax(keV)= "<< Tmax/keV << "  cut(keV)= " 
200     //     << cut/keV << "  E(MeV)= " << kinEnergy/MeV << G4endl;
201 
202     G4int n = fPAIxSection.GetSplineSize();
203 
204     auto transferVector = new G4PhysicsFreeVector(n);
205     auto photonVector   = new G4PhysicsFreeVector(n);
206     auto plasmonVector  = new G4PhysicsFreeVector(n);
207 
208     auto dEdxVector     = new G4PhysicsFreeVector(n);
209 
210     for( G4int k = 0; k < n; k++ )
211     {
212       G4double t = fPAIxSection.GetSplineEnergy(k+1);
213 
214       transferVector->PutValue(k , t, 
215                                t*fPAIxSection.GetIntegralPAIxSection(k+1));
216       photonVector->PutValue(k , t, 
217                                t*fPAIxSection.GetIntegralCerenkov(k+1));
218       plasmonVector->PutValue(k , t, 
219                                t*fPAIxSection.GetIntegralPlasmon(k+1));
220 
221       dEdxVector->PutValue(k, t, fPAIxSection.GetIntegralPAIdEdx(k+1));
222     }
223     // G4cout << *transferVector << G4endl;
224 
225     G4double ionloss = std::max(fPAIxSection.GetMeanEnergyLoss(), 0.0);//  total <dE/dx>
226     dEdxMeanVector->PutValue(i,ionloss);
227 
228     G4double dNdxCut = transferVector->Value(deltaCutInKineticEnergyNow)/deltaCutInKineticEnergyNow;
229     G4double dNdxCutPhoton = photonVector->Value(photonCutInKineticEnergyNow)/photonCutInKineticEnergyNow;
230     G4double dNdxCutPlasmon = plasmonVector->Value(deltaCutInKineticEnergyNow)/deltaCutInKineticEnergyNow;
231 
232     G4double dEdxCut = dEdxVector->Value(cut)/cut;
233     //G4cout << "i= " << i << " x= " << dNdxCut << G4endl;
234 
235     if(dNdxCut < 0.0) { dNdxCut = 0.0; }
236     if(dNdxCutPhoton < 0.0) { dNdxCutPhoton = 0.0; }
237     if(dNdxCutPlasmon < 0.0) { dNdxCutPlasmon = 0.0; }
238 
239     dNdxCutVector->PutValue(i, dNdxCut);
240     dNdxCutPhotonVector->PutValue(i, dNdxCutPhoton);
241     dNdxCutPlasmonVector->PutValue(i, dNdxCutPlasmon);
242 
243     dEdxCutVector->PutValue(i, dEdxCut);
244 
245     PAItransferTable->insertAt(i,transferVector);
246     PAIphotonTable->insertAt(i,photonVector);
247     PAIplasmonTable->insertAt(i,plasmonVector);
248     PAIdEdxTable->insertAt(i,dEdxVector);
249 
250   } // end of Tkin loop
251 
252   fPAIxscBank.push_back(PAItransferTable);
253   fPAIphotonBank.push_back(PAIphotonTable);
254   fPAIplasmonBank.push_back(PAIplasmonTable);
255 
256   fPAIdEdxBank.push_back(PAIdEdxTable);
257   fdEdxTable.push_back(dEdxMeanVector);
258 
259   fdNdxCutTable.push_back(dNdxCutVector);
260   fdNdxCutPhotonTable.push_back(dNdxCutPhotonVector);
261   fdNdxCutPlasmonTable.push_back(dNdxCutPlasmonVector);
262 
263   fdEdxCutTable.push_back(dEdxCutVector);
264 }
265 
266 //////////////////////////////////////////////////////////////////////////////
267 
268 G4double G4PAIPhotData::DEDXPerVolume(G4int coupleIndex, G4double scaledTkin,
269        G4double cut) const
270 {
271   // VI: iPlace is the low edge index of the bin
272   // iPlace is in interval from 0 to (N-1)
273   std::size_t iPlace = fParticleEnergyVector->FindBin(scaledTkin, 0);
274   std::size_t nPlace = fParticleEnergyVector->GetVectorLength() - 1;
275 
276   G4bool one = true;
277   if(scaledTkin >= fParticleEnergyVector->Energy(nPlace)) { iPlace = nPlace; }
278   else if(scaledTkin > fParticleEnergyVector->Energy(0)) { 
279     one = false; 
280   }
281 
282   // VI: apply interpolation of the vector
283   G4double dEdx = fdEdxTable[coupleIndex]->Value(scaledTkin);
284   G4double del  = (*(fPAIdEdxBank[coupleIndex]))(iPlace)->Value(cut);
285   if(!one) {
286     G4double del2 = (*(fPAIdEdxBank[coupleIndex]))(iPlace+1)->Value(cut);
287     G4double E1 = fParticleEnergyVector->Energy(iPlace); 
288     G4double E2 = fParticleEnergyVector->Energy(iPlace+1);
289     G4double W  = 1.0/(E2 - E1);
290     G4double W1 = (E2 - scaledTkin)*W;
291     G4double W2 = (scaledTkin - E1)*W;
292     del *= W1;
293     del += W2*del2;
294   }
295   dEdx -= del;
296 
297   if( dEdx < 0.) { dEdx = 0.; }
298   return dEdx;
299 }
300 
301 /////////////////////////////////////////////////////////////////////////
302 
303 G4double 
304 G4PAIPhotData::CrossSectionPerVolume(G4int coupleIndex, 
305               G4double scaledTkin,
306               G4double tcut, G4double tmax) const
307 {
308   G4double cross, xscEl, xscEl2, xscPh, xscPh2;
309 
310   cross=tcut+tmax;
311 
312   // iPlace is in interval from 0 to (N-1)
313 
314   std::size_t iPlace = fParticleEnergyVector->FindBin(scaledTkin, 0);
315   std::size_t nPlace = fParticleEnergyVector->GetVectorLength() - 1;
316 
317   G4bool one = true;
318 
319   if(      scaledTkin >= fParticleEnergyVector->Energy(nPlace))  iPlace = nPlace; 
320   else if( scaledTkin > fParticleEnergyVector->Energy(0)      )   one   = false; 
321   
322 
323   xscEl2 = (*fdNdxCutPlasmonTable[coupleIndex])(iPlace);
324   xscPh2 = (*fdNdxCutPhotonTable[coupleIndex])(iPlace);
325 
326   xscPh = xscPh2;
327   xscEl = xscEl2;
328 
329   cross  = xscPh + xscEl;
330  
331   if( !one ) 
332   {
333     xscEl2 = (*fdNdxCutPlasmonTable[coupleIndex])(iPlace+1);
334 
335     G4double E1 = fParticleEnergyVector->Energy(iPlace); 
336     G4double E2 = fParticleEnergyVector->Energy(iPlace+1);
337 
338     G4double W  = 1.0/(E2 - E1);
339     G4double W1 = (E2 - scaledTkin)*W;
340     G4double W2 = (scaledTkin - E1)*W;
341 
342     xscEl *= W1;
343     xscEl += W2*xscEl2;
344 
345     xscPh2 = (*fdNdxCutPhotonTable[coupleIndex])(iPlace+1);
346 
347     E1 = fParticleEnergyVector->Energy(iPlace); 
348     E2 = fParticleEnergyVector->Energy(iPlace+1);
349 
350     W  = 1.0/(E2 - E1);
351     W1 = (E2 - scaledTkin)*W;
352     W2 = (scaledTkin - E1)*W;
353 
354     xscPh *= W1;
355     xscPh += W2*xscPh2;
356 
357     cross = xscEl + xscPh;
358   }
359   if( cross < 0.0)  cross = 0.0; 
360 
361   return cross;
362 }
363 
364 /////////////////////////////////////////////////////////////////////////
365 
366 G4double 
367 G4PAIPhotData::GetPlasmonRatio(G4int coupleIndex, G4double scaledTkin) const
368 {
369   G4double cross, xscEl, xscEl2, xscPh, xscPh2, plRatio;
370   // iPlace is in interval from 0 to (N-1)
371 
372   std::size_t iPlace = fParticleEnergyVector->FindBin(scaledTkin, 0);
373   std::size_t nPlace = fParticleEnergyVector->GetVectorLength() - 1;
374 
375   G4bool one = true;
376 
377   if(      scaledTkin >= fParticleEnergyVector->Energy(nPlace))  iPlace = nPlace; 
378   else if( scaledTkin > fParticleEnergyVector->Energy(0)      )   one   = false; 
379   
380 
381   xscEl2 = (*fdNdxCutPlasmonTable[coupleIndex])(iPlace);
382   xscPh2 = (*fdNdxCutPhotonTable[coupleIndex])(iPlace);
383 
384   xscPh = xscPh2;
385   xscEl = xscEl2;
386 
387   cross  = xscPh + xscEl;
388  
389   if( !one ) 
390   {
391     xscEl2 = (*fdNdxCutPlasmonTable[coupleIndex])(iPlace+1);
392 
393     G4double E1 = fParticleEnergyVector->Energy(iPlace); 
394     G4double E2 = fParticleEnergyVector->Energy(iPlace+1);
395 
396     G4double W  = 1.0/(E2 - E1);
397     G4double W1 = (E2 - scaledTkin)*W;
398     G4double W2 = (scaledTkin - E1)*W;
399 
400     xscEl *= W1;
401     xscEl += W2*xscEl2;
402 
403     xscPh2 = (*fdNdxCutPhotonTable[coupleIndex])(iPlace+1);
404 
405     E1 = fParticleEnergyVector->Energy(iPlace); 
406     E2 = fParticleEnergyVector->Energy(iPlace+1);
407 
408     W  = 1.0/(E2 - E1);
409     W1 = (E2 - scaledTkin)*W;
410     W2 = (scaledTkin - E1)*W;
411 
412     xscPh *= W1;
413     xscPh += W2*xscPh2;
414 
415     cross = xscEl + xscPh;
416   }
417   if( cross <= 0.0)  
418   {
419     plRatio = 2.0; 
420   }
421   else
422   {
423     plRatio = xscEl/cross;
424 
425     if( plRatio > 1. || plRatio < 0.) plRatio = 2.0;
426   }
427   return plRatio;
428 }
429 
430 ///////////////////////////////////////////////////////////////////////
431 
432 G4double G4PAIPhotData::SampleAlongStepTransfer(G4int coupleIndex, 
433                                                  G4double kinEnergy,
434              G4double scaledTkin,
435              G4double stepFactor) const
436 {
437   G4double loss = 0.0;
438   G4double omega; 
439   G4double position, E1, E2, W1, W2, W, dNdxCut1, dNdxCut2, meanNumber;
440 
441   std::size_t iPlace = fParticleEnergyVector->FindBin(scaledTkin, 0);
442   std::size_t nPlace = fParticleEnergyVector->GetVectorLength() - 1;
443  
444   G4bool one = true;
445 
446   if     (scaledTkin >= fParticleEnergyVector->Energy(nPlace)) iPlace = nPlace; 
447   else if(scaledTkin > fParticleEnergyVector->Energy(0))          one = false; 
448 
449   G4PhysicsLogVector* vcut = fdNdxCutTable[coupleIndex];
450   G4PhysicsVector*      v1 = (*(fPAIxscBank[coupleIndex]))(iPlace);
451   G4PhysicsVector*      v2 = nullptr;
452 
453   dNdxCut1    = (*vcut)[iPlace];
454   G4double e1 = v1->Energy(0);
455   G4double e2 = e1;
456 
457   G4double meanN1 = ((*v1)[0]/e1 - dNdxCut1)*stepFactor;
458 
459   meanNumber = meanN1;
460 
461   // G4cout<<"iPlace = "<<iPlace<< " meanN1= " << meanN1 
462   //  <<"    (*v1)[0]/e1 = "<<(*v1)[0]/e1<< " dNdxCut1= " << dNdxCut1 << G4endl;
463 
464   dNdxCut2 = dNdxCut1;
465   W1 = 1.0;
466   W2 = 0.0;
467   if(!one) 
468   {
469     v2 = (*(fPAIxscBank[coupleIndex]))(iPlace+1);
470     dNdxCut2 = (*vcut)[iPlace+1];
471     e2 = v2->Energy(0);
472 
473     G4double meanN2 = ((*v2)[0]/e2 - dNdxCut2)*stepFactor;
474 
475     E1 = fParticleEnergyVector->Energy(iPlace); 
476     E2 = fParticleEnergyVector->Energy(iPlace+1);
477     W = 1.0/(E2 - E1);
478     W1 = (E2 - scaledTkin)*W;
479     W2 = (scaledTkin - E1)*W;
480     meanNumber = W1*meanN1 + W2*meanN2;
481 
482     //G4cout<<"meanN= " <<  meanNumber << " meanN2= " << meanN2 
483     //    << " dNdxCut2= " << dNdxCut2 << G4endl;
484   }
485   if( meanNumber <= 0.0) return 0.0; 
486 
487   G4int numOfCollisions = (G4int)G4Poisson(meanNumber);
488 
489   //G4cout << "N= " << numOfCollisions << G4endl;
490 
491   if( 0 == numOfCollisions) return 0.0; 
492 
493   for(G4int i=0; i< numOfCollisions; ++i) 
494   {
495     G4double rand = G4UniformRand();
496     position = dNdxCut1 + ((*v1)[0]/e1 - dNdxCut1)*rand;
497     omega = GetEnergyTransfer(coupleIndex, iPlace, position);
498 
499     //G4cout << "omega(keV)= " << omega/keV << G4endl;
500 
501     if(!one) 
502     {
503       position = dNdxCut2 + ((*v2)[0]/e2 - dNdxCut2)*rand;
504       G4double omega2 = GetEnergyTransfer(coupleIndex, iPlace+1, position);
505       omega = omega*W1 + omega2*W2;
506     }
507     //G4cout << "omega(keV)= " << omega/keV << G4endl;
508 
509     loss += omega;
510     if( loss > kinEnergy) { break; }
511   }
512   
513   // G4cout<<"PAIPhotData AlongStepLoss = "<<loss/keV<<" keV, on step = "
514   //<<step/mm<<" mm"<<G4endl; 
515 
516   if     ( loss > kinEnergy) loss = kinEnergy; 
517   else if( loss < 0.)        loss = 0.;
518  
519   return loss;
520 }
521 
522 ////////////////////////////////////////////////////////////////////////
523 
524 G4double G4PAIPhotData::SampleAlongStepPhotonTransfer(G4int coupleIndex, 
525                                                  G4double kinEnergy,
526              G4double scaledTkin,
527              G4double stepFactor) const
528 {
529   G4double loss = 0.0;
530   G4double omega; 
531   G4double position, E1, E2, W1, W2, W, dNdxCut1, dNdxCut2, meanNumber;
532 
533   std::size_t iPlace = fParticleEnergyVector->FindBin(scaledTkin, 0);
534   std::size_t nPlace = fParticleEnergyVector->GetVectorLength() - 1;
535  
536   G4bool one = true;
537 
538   if     (scaledTkin >= fParticleEnergyVector->Energy(nPlace)) iPlace = nPlace; 
539   else if(scaledTkin > fParticleEnergyVector->Energy(0))          one = false; 
540 
541   G4PhysicsLogVector* vcut = fdNdxCutPhotonTable[coupleIndex];
542   G4PhysicsVector*      v1 = (*(fPAIphotonBank[coupleIndex]))(iPlace);
543   G4PhysicsVector*      v2 = nullptr;
544 
545   dNdxCut1    = (*vcut)[iPlace];
546   G4double e1 = v1->Energy(0);
547   G4double e2 = e1;
548 
549   G4double meanN1 = ((*v1)[0]/e1 - dNdxCut1)*stepFactor;
550 
551   meanNumber = meanN1;
552 
553   // G4cout<<"iPlace = "<<iPlace<< " meanN1= " << meanN1 
554   //  <<"    (*v1)[0]/e1 = "<<(*v1)[0]/e1<< " dNdxCut1= " << dNdxCut1 << G4endl;
555 
556   dNdxCut2 = dNdxCut1;
557   W1 = 1.0;
558   W2 = 0.0;
559   if(!one) 
560   {
561     v2 = (*(fPAIphotonBank[coupleIndex]))(iPlace+1);
562     dNdxCut2 = (*vcut)[iPlace+1];
563     e2 = v2->Energy(0);
564 
565     G4double meanN2 = ((*v2)[0]/e2 - dNdxCut2)*stepFactor;
566 
567     E1 = fParticleEnergyVector->Energy(iPlace); 
568     E2 = fParticleEnergyVector->Energy(iPlace+1);
569     W = 1.0/(E2 - E1);
570     W1 = (E2 - scaledTkin)*W;
571     W2 = (scaledTkin - E1)*W;
572     meanNumber = W1*meanN1 + W2*meanN2;
573 
574     //G4cout<<"meanN= " <<  meanNumber << " meanN2= " << meanN2 
575     //    << " dNdxCut2= " << dNdxCut2 << G4endl;
576   }
577   if( meanNumber <= 0.0) return 0.0; 
578 
579   G4int numOfCollisions = (G4int)G4Poisson(meanNumber);
580 
581   //G4cout << "N= " << numOfCollisions << G4endl;
582 
583   if( 0 == numOfCollisions) return 0.0; 
584 
585   for(G4int i=0; i< numOfCollisions; ++i) 
586   {
587     G4double rand = G4UniformRand();
588     position = dNdxCut1 + ((*v1)[0]/e1 - dNdxCut1)*rand;
589     omega = GetEnergyPhotonTransfer(coupleIndex, iPlace, position);
590 
591     //G4cout << "omega(keV)= " << omega/keV << G4endl;
592 
593     if(!one) 
594     {
595       position = dNdxCut2 + ((*v2)[0]/e2 - dNdxCut2)*rand;
596       G4double omega2 = GetEnergyPhotonTransfer(coupleIndex, iPlace+1, position);
597       omega = omega*W1 + omega2*W2;
598     }
599     //G4cout << "omega(keV)= " << omega/keV << G4endl;
600 
601     loss += omega;
602     if( loss > kinEnergy) { break; }
603   }
604   
605   // G4cout<<"PAIPhotData AlongStepLoss = "<<loss/keV<<" keV, on step = "
606   //<<step/mm<<" mm"<<G4endl; 
607 
608   if     ( loss > kinEnergy) loss = kinEnergy; 
609   else if( loss < 0.)        loss = 0.;
610  
611   return loss;
612 }
613 
614 //////////////////////////////////////////////////////////////////
615 
616 G4double G4PAIPhotData::SampleAlongStepPlasmonTransfer(G4int coupleIndex, 
617                                                  G4double kinEnergy,
618              G4double scaledTkin,
619              G4double stepFactor) const
620 {
621   G4double loss = 0.0;
622   G4double omega; 
623   G4double position, E1, E2, W1, W2, W, dNdxCut1, dNdxCut2, meanNumber;
624 
625   std::size_t iPlace = fParticleEnergyVector->FindBin(scaledTkin, 0);
626   std::size_t nPlace = fParticleEnergyVector->GetVectorLength() - 1;
627  
628   G4bool one = true;
629 
630   if     (scaledTkin >= fParticleEnergyVector->Energy(nPlace)) iPlace = nPlace; 
631   else if(scaledTkin > fParticleEnergyVector->Energy(0))          one = false; 
632 
633   G4PhysicsLogVector* vcut = fdNdxCutPlasmonTable[coupleIndex];
634   G4PhysicsVector*      v1 = (*(fPAIplasmonBank[coupleIndex]))(iPlace);
635   G4PhysicsVector*      v2 = nullptr;
636 
637   dNdxCut1    = (*vcut)[iPlace];
638   G4double e1 = v1->Energy(0);
639   G4double e2 = e1;
640 
641   G4double meanN1 = ((*v1)[0]/e1 - dNdxCut1)*stepFactor;
642 
643   meanNumber = meanN1;
644 
645   // G4cout<<"iPlace = "<<iPlace<< " meanN1= " << meanN1 
646   //  <<"    (*v1)[0]/e1 = "<<(*v1)[0]/e1<< " dNdxCut1= " << dNdxCut1 << G4endl;
647 
648   dNdxCut2 = dNdxCut1;
649   W1 = 1.0;
650   W2 = 0.0;
651   if(!one) 
652   {
653     v2 = (*(fPAIplasmonBank[coupleIndex]))(iPlace+1);
654     dNdxCut2 = (*vcut)[iPlace+1];
655     e2 = v2->Energy(0);
656 
657     G4double meanN2 = ((*v2)[0]/e2 - dNdxCut2)*stepFactor;
658 
659     E1 = fParticleEnergyVector->Energy(iPlace); 
660     E2 = fParticleEnergyVector->Energy(iPlace+1);
661     W = 1.0/(E2 - E1);
662     W1 = (E2 - scaledTkin)*W;
663     W2 = (scaledTkin - E1)*W;
664     meanNumber = W1*meanN1 + W2*meanN2;
665 
666     //G4cout<<"meanN= " <<  meanNumber << " meanN2= " << meanN2 
667     //    << " dNdxCut2= " << dNdxCut2 << G4endl;
668   }
669   if( meanNumber <= 0.0) return 0.0; 
670 
671   G4int numOfCollisions = (G4int)G4Poisson(meanNumber);
672 
673   //G4cout << "N= " << numOfCollisions << G4endl;
674 
675   if( 0 == numOfCollisions) return 0.0; 
676 
677   for(G4int i=0; i< numOfCollisions; ++i) 
678   {
679     G4double rand = G4UniformRand();
680     position = dNdxCut1 + ((*v1)[0]/e1 - dNdxCut1)*rand;
681     omega = GetEnergyPlasmonTransfer(coupleIndex, iPlace, position);
682 
683     //G4cout << "omega(keV)= " << omega/keV << G4endl;
684 
685     if(!one) 
686     {
687       position = dNdxCut2 + ((*v2)[0]/e2 - dNdxCut2)*rand;
688       G4double omega2 = GetEnergyPlasmonTransfer(coupleIndex, iPlace+1, position);
689       omega = omega*W1 + omega2*W2;
690     }
691     //G4cout << "omega(keV)= " << omega/keV << G4endl;
692 
693     loss += omega;
694     if( loss > kinEnergy) { break; }
695   }
696   
697   // G4cout<<"PAIPhotData AlongStepLoss = "<<loss/keV<<" keV, on step = "
698   //<<step/mm<<" mm"<<G4endl; 
699 
700   if     ( loss > kinEnergy) loss = kinEnergy; 
701   else if( loss < 0.)        loss = 0.;
702  
703   return loss;
704 }
705 
706 ///////////////////////////////////////////////////////////////////////
707 //
708 // Returns post step PAI energy transfer > cut electron energy 
709 // according to passed scaled kinetic energy of particle
710 
711 G4double G4PAIPhotData::SamplePostStepTransfer(G4int coupleIndex, 
712             G4double scaledTkin) const
713 {  
714   //G4cout<<"G4PAIPhotData::GetPostStepTransfer"<<G4endl;
715   G4double transfer = 0.0;
716   G4double rand = G4UniformRand();
717 
718   std::size_t nPlace = fParticleEnergyVector->GetVectorLength() - 1;
719 
720   //  std::size_t iTransfer, iTr1, iTr2;
721   G4double position, dNdxCut1, dNdxCut2, E1, E2, W1, W2, W;
722 
723   G4PhysicsVector* cutv = fdNdxCutTable[coupleIndex];
724 
725   // Fermi plato, try from left
726   if( scaledTkin >= fParticleEnergyVector->GetMaxEnergy()) 
727   {
728     position = (*cutv)[nPlace]*rand;
729     transfer = GetEnergyTransfer(coupleIndex, nPlace, position);
730   }
731   else if( scaledTkin <= fParticleEnergyVector->Energy(0) )
732   {
733     position = (*cutv)[0]*rand;
734     transfer = GetEnergyTransfer(coupleIndex, 0, position);
735   }
736   else 
737   {  
738     std::size_t iPlace = fParticleEnergyVector->FindBin(scaledTkin, 0);
739 
740     dNdxCut1 = (*cutv)[iPlace];  
741     dNdxCut2 = (*cutv)[iPlace+1];  
742 
743     E1 = fParticleEnergyVector->Energy(iPlace); 
744     E2 = fParticleEnergyVector->Energy(iPlace+1);
745     W  = 1.0/(E2 - E1);
746     W1 = (E2 - scaledTkin)*W;
747     W2 = (scaledTkin - E1)*W;
748 
749     //G4cout<<"iPlace= " << "  dNdxCut1 = "<<dNdxCut1 
750     //    <<" dNdxCut2 = "<<dNdxCut2<< " W1= " << W1 << " W2= " << W2 <<G4endl;
751 
752     position = dNdxCut1*rand;
753     G4double tr1 = GetEnergyTransfer(coupleIndex, iPlace, position);
754 
755     position = dNdxCut2*rand;
756     G4double tr2 = GetEnergyTransfer(coupleIndex, iPlace+1, position);
757 
758     transfer = tr1*W1 + tr2*W2;
759   }
760   //G4cout<<"PAImodel PostStepTransfer = "<<transfer/keV<<" keV"<<G4endl; 
761   if(transfer < 0.0 ) { transfer = 0.0; }
762   return transfer;
763 }
764 
765 ////////////////////////////////////////////////////////////////////////
766 
767 G4double G4PAIPhotData::SamplePostStepPhotonTransfer(G4int coupleIndex, 
768             G4double scaledTkin) const
769 {  
770   //G4cout<<"G4PAIPhotData::GetPostStepTransfer"<<G4endl;
771   G4double transfer = 0.0;
772   G4double rand = G4UniformRand();
773 
774   std::size_t nPlace = fParticleEnergyVector->GetVectorLength() - 1;
775 
776   //  std::size_t iTransfer, iTr1, iTr2;
777   G4double position, dNdxCut1, dNdxCut2, E1, E2, W1, W2, W;
778 
779   G4PhysicsVector* cutv = fdNdxCutPhotonTable[coupleIndex];
780 
781   // Fermi plato, try from left
782 
783   if( scaledTkin >= fParticleEnergyVector->GetMaxEnergy()) 
784   {
785     position = (*cutv)[nPlace]*rand;
786     transfer = GetEnergyPhotonTransfer(coupleIndex, nPlace, position);
787   }
788   else if( scaledTkin <= fParticleEnergyVector->Energy(0) )
789   {
790     position = (*cutv)[0]*rand;
791     transfer = GetEnergyPhotonTransfer(coupleIndex, 0, position);
792   }
793   else 
794   {  
795     std::size_t iPlace = fParticleEnergyVector->FindBin(scaledTkin, 0);
796 
797     dNdxCut1 = (*cutv)[iPlace];  
798     dNdxCut2 = (*cutv)[iPlace+1];  
799 
800     E1 = fParticleEnergyVector->Energy(iPlace); 
801     E2 = fParticleEnergyVector->Energy(iPlace+1);
802     W  = 1.0/(E2 - E1);
803     W1 = (E2 - scaledTkin)*W;
804     W2 = (scaledTkin - E1)*W;
805 
806     //G4cout<<"iPlace= " << "  dNdxCut1 = "<<dNdxCut1 
807     //    <<" dNdxCut2 = "<<dNdxCut2<< " W1= " << W1 << " W2= " << W2 <<G4endl;
808 
809     position = dNdxCut1*rand;
810 
811     G4double tr1 = GetEnergyPhotonTransfer(coupleIndex, iPlace, position);
812 
813     position = dNdxCut2*rand;
814     G4double tr2 = GetEnergyPhotonTransfer(coupleIndex, iPlace+1, position);
815 
816     transfer = tr1*W1 + tr2*W2;
817   }
818   //G4cout<<"PAImodel PostStepTransfer = "<<transfer/keV<<" keV"<<G4endl; 
819   if(transfer < 0.0 ) { transfer = 0.0; }
820   return transfer;
821 }
822 
823 //////////////////////////////////////////////////////////////////////////
824 
825 G4double G4PAIPhotData::SamplePostStepPlasmonTransfer(G4int coupleIndex, 
826             G4double scaledTkin) const
827 {  
828   //G4cout<<"G4PAIPhotData::GetPostStepTransfer"<<G4endl;
829   G4double transfer = 0.0;
830   G4double rand = G4UniformRand();
831 
832   std::size_t nPlace = fParticleEnergyVector->GetVectorLength() - 1;
833 
834   //  std::size_t iTransfer, iTr1, iTr2;
835   G4double position, dNdxCut1, dNdxCut2, E1, E2, W1, W2, W;
836 
837   G4PhysicsVector* cutv = fdNdxCutPlasmonTable[coupleIndex];
838 
839   // Fermi plato, try from left
840   if( scaledTkin >= fParticleEnergyVector->GetMaxEnergy()) 
841   {
842     position = (*cutv)[nPlace]*rand;
843     transfer = GetEnergyPlasmonTransfer(coupleIndex, nPlace, position);
844   }
845   else if( scaledTkin <= fParticleEnergyVector->Energy(0) )
846   {
847     position = (*cutv)[0]*rand;
848     transfer = GetEnergyPlasmonTransfer(coupleIndex, 0, position);
849   }
850   else 
851   {  
852     std::size_t iPlace = fParticleEnergyVector->FindBin(scaledTkin, 0);
853 
854     dNdxCut1 = (*cutv)[iPlace];  
855     dNdxCut2 = (*cutv)[iPlace+1];  
856 
857     E1 = fParticleEnergyVector->Energy(iPlace); 
858     E2 = fParticleEnergyVector->Energy(iPlace+1);
859     W  = 1.0/(E2 - E1);
860     W1 = (E2 - scaledTkin)*W;
861     W2 = (scaledTkin - E1)*W;
862 
863     //G4cout<<"iPlace= " << "  dNdxCut1 = "<<dNdxCut1 
864     //    <<" dNdxCut2 = "<<dNdxCut2<< " W1= " << W1 << " W2= " << W2 <<G4endl;
865 
866     position = dNdxCut1*rand;
867     G4double tr1 = GetEnergyPlasmonTransfer(coupleIndex, iPlace, position);
868 
869     position = dNdxCut2*rand;
870     G4double tr2 = GetEnergyPlasmonTransfer(coupleIndex, iPlace+1, position);
871 
872     transfer = tr1*W1 + tr2*W2;
873   }
874   //G4cout<<"PAImodel PostStepPlasmonTransfer = "<<transfer/keV<<" keV"<<G4endl; 
875 
876   if(transfer < 0.0 )  transfer = 0.0;
877  
878   return transfer;
879 }
880 
881 ///////////////////////////////////////////////////////////////////////
882 //
883 // Returns PAI energy transfer according to passed 
884 // indexes of particle kinetic enegry and random x-section
885 
886 G4double G4PAIPhotData::GetEnergyTransfer(G4int coupleIndex, 
887            std::size_t iPlace, 
888            G4double position) const
889 { 
890   G4PhysicsVector* v = (*(fPAIxscBank[coupleIndex]))(iPlace); 
891   if(position*v->Energy(0) >= (*v)[0]) { return v->Energy(0); }
892 
893   std::size_t iTransferMax = v->GetVectorLength() - 1;
894 
895   std::size_t iTransfer;
896   G4double x1(0.0), x2(0.0), y1(0.0), y2(0.0), energyTransfer;
897 
898   for(iTransfer=1; iTransfer<=iTransferMax; ++iTransfer) {
899     x2 = v->Energy(iTransfer);
900     y2 = (*v)[iTransfer]/x2;
901     if(position >= y2) { break; }
902   }
903 
904   x1 = v->Energy(iTransfer-1);
905   y1 = (*v)[iTransfer-1]/x1;
906   //G4cout << "i= " << iTransfer << " imax= " << iTransferMax
907   //   << " x1= " << x1 << " x2= " << x2 << G4endl;
908 
909   energyTransfer = x1;
910   if ( x1 != x2 ) {
911     if ( y1 == y2  ) {
912       energyTransfer += (x2 - x1)*G4UniformRand();
913     } else {
914       if(x1*1.1 < x2) {
915   const G4int nbins = 5;
916         G4double del = (x2 - x1)/G4int(nbins);
917         x2  = x1;
918         for(G4int i=1; i<=nbins; ++i) {
919           x2 += del;
920           y2 = v->Value(x2)/x2;
921           if(position >= y2) { break; }
922           x1 = x2;
923           y1 = y2;
924   }
925       }
926       energyTransfer = (y2 - y1)*x1*x2/(position*(x1 - x2) - y1*x1 + y2*x2);
927     }
928   }
929   //  G4cout << "x1(keV)= " << x1/keV << " x2(keV)= " << x2/keV
930   //   << " y1= " << y1 << " y2= " << y2 << " pos= " << position
931   //   << " E(keV)= " << energyTransfer/keV << G4endl; 
932   return energyTransfer;
933 }
934 
935 /////////////////////////////////////////////////////////////////
936 
937 G4double G4PAIPhotData::GetEnergyPhotonTransfer(G4int coupleIndex, 
938                   std::size_t iPlace, 
939                   G4double position) const
940 { 
941   G4PhysicsVector* v = (*(fPAIphotonBank[coupleIndex]))(iPlace); 
942   if(position*v->Energy(0) >= (*v)[0])  return v->Energy(0); 
943 
944   std::size_t iTransferMax = v->GetVectorLength() - 1;
945 
946   std::size_t iTransfer;
947   G4double x1(0.0), x2(0.0), y1(0.0), y2(0.0), energyTransfer;
948 
949   for(iTransfer=1; iTransfer<=iTransferMax; ++iTransfer) 
950   {
951     x2 = v->Energy(iTransfer);
952     y2 = (*v)[iTransfer]/x2;
953     if(position >= y2)  break; 
954   }
955   x1 = v->Energy(iTransfer-1);
956   y1 = (*v)[iTransfer-1]/x1;
957 
958   //G4cout << "i= " << iTransfer << " imax= " << iTransferMax
959   //   << " x1= " << x1 << " x2= " << x2 << G4endl;
960 
961   energyTransfer = x1;
962 
963   if ( x1 != x2 ) 
964   {
965     if ( y1 == y2  ) 
966     {
967       energyTransfer += (x2 - x1)*G4UniformRand();
968     } 
969     else 
970     {
971       if( x1*1.1 < x2 ) 
972       {
973   const G4int nbins = 5;
974         G4double del = (x2 - x1)/G4int(nbins);
975         x2  = x1;
976 
977         for(G4int i=1; i<=nbins; ++i) 
978         {
979           x2 += del;
980           y2 = v->Value(x2)/x2;
981           if(position >= y2) { break; }
982           x1 = x2;
983           y1 = y2;
984   }
985       }
986       energyTransfer = (y2 - y1)*x1*x2/(position*(x1 - x2) - y1*x1 + y2*x2);
987     }
988   }
989   //  G4cout << "x1(keV)= " << x1/keV << " x2(keV)= " << x2/keV
990   //   << " y1= " << y1 << " y2= " << y2 << " pos= " << position
991   //   << " E(keV)= " << energyTransfer/keV << G4endl;
992  
993   return energyTransfer;
994 }
995 
996 /////////////////////////////////////////////////////////////////////////
997 
998 G4double G4PAIPhotData::GetEnergyPlasmonTransfer(G4int coupleIndex, 
999                    std::size_t iPlace, 
1000                    G4double position) const
1001 { 
1002   G4PhysicsVector* v = (*(fPAIplasmonBank[coupleIndex]))(iPlace); 
1003 
1004   if( position*v->Energy(0) >= (*v)[0] )  return v->Energy(0); 
1005 
1006   std::size_t iTransferMax = v->GetVectorLength() - 1;
1007 
1008   std::size_t iTransfer;
1009   G4double x1(0.0), x2(0.0), y1(0.0), y2(0.0), energyTransfer;
1010 
1011   for(iTransfer = 1; iTransfer <= iTransferMax; ++iTransfer) 
1012   {
1013     x2 = v->Energy(iTransfer);
1014     y2 = (*v)[iTransfer]/x2;
1015     if(position >= y2)  break; 
1016   }
1017   x1 = v->Energy(iTransfer-1);
1018   y1 = (*v)[iTransfer-1]/x1;
1019 
1020   //G4cout << "i= " << iTransfer << " imax= " << iTransferMax
1021   //   << " x1= " << x1 << " x2= " << x2 << G4endl;
1022 
1023   energyTransfer = x1;
1024 
1025   if ( x1 != x2 ) 
1026   {
1027     if ( y1 == y2  ) 
1028     {
1029       energyTransfer += (x2 - x1)*G4UniformRand();
1030     } 
1031     else 
1032     {
1033       if(x1*1.1 < x2) 
1034       {
1035   const G4int nbins = 5;
1036         G4double del = (x2 - x1)/G4int(nbins);
1037         x2  = x1;
1038 
1039         for( G4int i = 1; i <= nbins; ++i ) 
1040         {
1041           x2 += del;
1042           y2 = v->Value(x2)/x2;
1043 
1044           if(position >= y2)  break; 
1045 
1046           x1 = x2;
1047           y1 = y2;
1048   }
1049       }
1050       energyTransfer = (y2 - y1)*x1*x2/(position*(x1 - x2) - y1*x1 + y2*x2);
1051     }
1052   }
1053   //  G4cout << "x1(keV)= " << x1/keV << " x2(keV)= " << x2/keV
1054   //   << " y1= " << y1 << " y2= " << y2 << " pos= " << position
1055   //   << " E(keV)= " << energyTransfer/keV << G4endl; 
1056 
1057   return energyTransfer;
1058 }
1059 
1060 //
1061 //
1062 //////////////////////////////////////////////////////////////////////
1063 
1064